事務 與 資料庫連線池【c3p0】 與 DBUtiles學習筆記
1.事務
開啟事務:start transaction;
回滾事務:rollback;
提交事務: commit;
關閉自動提交事務:setAutoCommit(false);
1.1事務的特性ACID【面試】
1.原子性【A】:事務包含的邏輯不可分割
一致性【C】:事務執行前後,資料完整性
隔離性【I】 :事務執行期間不受其他事務影響
永續性【D】:事務執行成功,則資料永久儲存到磁碟上;
1.1.2.事務的安全隱患:
不考慮隔離級別設定:
【讀】:
1.髒讀:>>>一個事務讀到另外一個事務還未提交的資料;
2.不可重複讀:>>>一個事務讀到了另外一個事務提交的資料,造成兩次查詢結果不一致;>>>解決:重複讀:repeatable read
3.幻讀:一個事務讀到另外一個事務已提交插入的資料,導致多次查詢結果不一致。>>>>解決:Serializable【可序列化】最高級別
四個隔離級別的效率從高到低排列:
讀未提交>讀已提交>可重複讀>可序列化
攔截程度相反
【寫】:丟失更新
>>>解決:1.悲觀鎖;
======== 2.樂觀鎖
【mysql預設隔離級別:可重複讀】
【oracle預設隔離級別:讀已提交】
1.1.3在程式碼中使用事務的步驟
Connection conn = JDBCUtil.getConn(); conn.setAutoCommit(false);//關閉事務的自動提交 ..... conn.commit();//提交 conn.roolback();//回滾
2.資料庫連線池
2.1DBCP連線池【瞭解】
dbcp建立dataSource方式:
BasicDataSource dataSource = new BasicDataSource();
2.1.1使用程式碼方式連線【瞭解】
將資料插入到bank下的account表中
public class demo1 { @Test public void dbcp(){ Connection conn = null; PreparedStatement ps = null; try { //1.構建資料來源物件 BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost/bank"); dataSource.setUsername("root"); dataSource.setPassword("123456"); //2.獲得連線物件 conn = dataSource.getConnection(); String sql = "insert into account values(null,?,?)"; ps = conn.prepareStatement(sql); ps.setString(1, "admin"); ps.setInt(2, 20000); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally{ JDBCUtil.release(conn, ps); } } }
2.1.2使用配置檔案方式
2.2 c3p0連線池【掌握】
c3p0建立dataSource連線方式:
ComboPooledDataSource dataSource = new ComboPooledDataSource();
2.2.1程式碼連線【瞭解】
public class demo1 {
@Test
public void c3p0() throws PropertyVetoException{
Connection conn = null;
PreparedStatement ps = null;
try {
//1.建立dataSource
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2.設定連線資料資訊
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
dataSource.setUser("root");
dataSource.setPassword("123456");
conn = dataSource.getConnection();
String sql = "insert into account values(null,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "aaa");
ps.setInt(2, 12000);
ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps);
}
}
}
2.2.2c3p0配置檔案連線方式【★掌握】
c3p0-config.xml的原始檔
<c3p0-config>
<default-config>
<property name="automaticTestTable">con_test</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
<user-overrides user="test-user">
<property name="maxPoolSize">10</property>
<property name="minPoolSize">1</property>
<property name="maxStatements">0</property>
</user-overrides>
</default-config>
<!-- This app is massive! -->
<named-config name="intergalactoApp">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property>
<!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
<!-- he's important, but there's only one of him -->
<user-overrides user="master-of-the-universe">
<property name="acquireIncrement">1</property>
<property name="initialPoolSize">1</property>
<property name="minPoolSize">1</property>
<property name="maxPoolSize">5</property>
<property name="maxStatementsPerConnection">50</property>
</user-overrides>
</named-config>
</c3p0-config>
所以我們在定義c3p0配置檔案時必須也使用c3p0-config.xml這個名字
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost/bank</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
</c3p0-config>
c3p0_demo2.java
public class c3p0_demo2 {
@Test
public void test(){
Connection conn = null;
PreparedStatement ps = null;
try {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//獲得連線物件
conn = dataSource.getConnection();
String sql = "insert into account values(null,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "c3p0");
ps.setInt(2, 18000);
ps.executeUpdate();//執行
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps);//釋放
}
}
}
執行後資料庫情況
這裡就把資料插進來了。
【特別注意】xml檔案的命名一定是:c3p0-config.xml,否則就會執行失敗
3.DBUtiles
QueryRunner
//1.c3p0建立連線
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2.dbUtil只是簡化CRUD的程式碼,但是不可以建立連線
QueryRunner run = new QueryRunner(dataSource);
兩個常用的方法:
1.queryRunner.update();//增刪改
2.queryRunner.query();//查詢
3.1DBUtiles裡的增刪改
dbUtil只是簡化CRUD的程式碼,但是不可以建立連線
public class Tset {
@Test
public void testInsert() throws SQLException{
//1.c3p0建立連線
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2.dbUtil只是簡化CRUD的程式碼,但是不可以建立連線
QueryRunner run = new QueryRunner(dataSource);
String sql = "insert into account values(null,?,?)";
//3.增加
run.update(sql, "dbutil",230000);
//4.刪除
run.update("delete from account where id = ?", 8);
//5.更新
run.update("update account set money=? where id=?", 20000,4);
}
}
3.2DBUtiles通用的增刪改方法
通過元資料獲取有幾個?(即佔位符)
ParameterMetaData metaData = ps.getParameterMetaData();
int count = metaData.getParameterCount();
public void test(){
update("insert into account values(null,?,?)", "common",100000);
}
public class CommonUtil {
public void update(String sql,Object...args){
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JDBCUtil.getConn();
ps = conn.prepareStatement(sql);
ParameterMetaData metaData = ps.getParameterMetaData();//獲取元資料
int count = metaData.getParameterCount();//獲取個數,這裡獲取?的個數
for (int i = 0; i < count; i++) {
ps.setObject(i+1, args[i]);
}
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtil.release(conn, ps);
}
}
}
3.3DBUtiles裡的查詢
這裡用到泛型,現在Domain層建立一個Account類:
生成set,get方法,重寫String
private String name;
private int money;
(一)程式碼實現
1.查詢單條資料
new BeanHandler<‘T’>(class檔案);
public class Select {
@Test
public void selectDemo() throws SQLException{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
QueryRunner runner = new QueryRunner(dataSource);
//查詢單條資料
Account account = runner.query("select * from account where id=?",
new BeanHandler<Account>(Account.class), 9);
System.out.println(account);
}
}
Account [name=dbutil, money=230000]
2.查詢多條資料
new BeanListHandler<‘T’>(class);
public class Select {
@Test
public void selectDemo() throws SQLException{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
QueryRunner runner = new QueryRunner(dataSource);
//查詢單條資料
List<Account> list= runner.query("select * from account",
new BeanListHandler<Account>(Account.class));
System.out.println(list);
}
}
[Account [name=張三, money=23000], Account [name=李四, money=25000], Account [name=admin, money=20000], Account [name=aaa, money=20000], Account [name=c3p0, money=18000], Account [name=dbutil, money=230000], Account [name=dbutil, money=230000], Account [name=dbutil, money=230000], Account [name=dbutil, money=230000]]