1. 事務(wù)
Transaction 其實(shí)指的一組操作柱恤,里面包含許多個(gè)單一的邏輯。只要有一個(gè)邏輯沒(méi)有執(zhí)行成功找爱,那么都算失敗梗顺。 所有的數(shù)據(jù)都回歸到最初的狀態(tài)(回滾)
- 為什么要有事務(wù)?
為了確保邏輯的成功。 例子: 銀行的轉(zhuǎn)賬车摄。
1.1 使用命令行方式演示事務(wù)寺谤。
- 開(kāi)啟事務(wù)
start transaction;
- 提交或者回滾事務(wù)
commit; 提交事務(wù), 數(shù)據(jù)將會(huì)寫(xiě)到磁盤(pán)上的數(shù)據(jù)庫(kù)
rollback ; 數(shù)據(jù)回滾吮播,回到最初的狀態(tài)变屁。
-
關(guān)閉自動(dòng)提交功能。
-
演示事務(wù)
1.2 使用代碼方式演示事務(wù)
代碼里面的事務(wù)意狠,主要是針對(duì)連接來(lái)的粟关。
- 通過(guò)conn.setAutoCommit(false )來(lái)關(guān)閉自動(dòng)提交的設(shè)置。
- 提交事務(wù) conn.commit();
- 回滾事務(wù) conn.rollback();
@Test
public void testTransaction(){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBCUtil.getConn();
//連接环戈,事務(wù)默認(rèn)就是自動(dòng)提交的闷板。 關(guān)閉自動(dòng)提交。
conn.setAutoCommit(false);
String sql = "update account set money = money - ? where id = ?";
ps = conn.prepareStatement(sql);
//扣錢(qián)院塞, 扣ID為1 的100塊錢(qián)
ps.setInt(1, 100);
ps.setInt(2, 1);
ps.executeUpdate();
int a = 10 /0 ;
//加錢(qián)遮晚, 給ID為2 加100塊錢(qián)
ps.setInt(1, -100);
ps.setInt(2, 2);
ps.executeUpdate();
//成功: 提交事務(wù)。
conn.commit();
} catch (SQLException e) {
try {
//事變: 回滾事務(wù)
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps, rs);
}
}
1.3 事務(wù)的特性
- 原子性
指的是 事務(wù)中包含的邏輯拦止,不可分割县遣。
- 一致性
指的是 事務(wù)執(zhí)行前后。數(shù)據(jù)完整性
- 隔離性
指的是 事務(wù)在執(zhí)行期間不應(yīng)該受到其他事務(wù)的影響
- 持久性
指的是 事務(wù)執(zhí)行成功创泄,那么數(shù)據(jù)應(yīng)該持久保存到磁盤(pán)上艺玲。
1.4 事務(wù)的安全隱患
不考慮隔離級(jí)別設(shè)置,那么會(huì)出現(xiàn)以下問(wèn)題鞠抑。
讀
- 臟讀:一個(gè)事務(wù)讀到另外一個(gè)事務(wù)還未提交的數(shù)據(jù)。
- 不可重復(fù)讀:一個(gè)事務(wù)讀到了另外一個(gè)事務(wù)提交的數(shù)據(jù) 忌警,造成了前后兩次查詢結(jié)果不一致搁拙。
- 幻讀:一個(gè)事務(wù)讀到了另一個(gè)事務(wù)insert的數(shù)據(jù) 秒梳,造成前后查詢結(jié)果不一致 。
寫(xiě)
- 丟失更新
1.5 可串行化
如果有一個(gè)連接的隔離級(jí)別設(shè)置為了串行化 箕速,那么誰(shuí)先打開(kāi)了事務(wù)酪碘, 誰(shuí)就有了先執(zhí)行的權(quán)利, 誰(shuí)后打開(kāi)事務(wù)盐茎,誰(shuí)就只能得著兴垦,等前面的那個(gè)事務(wù),提交或者回滾后字柠,才能執(zhí)行探越。 但是這種隔離級(jí)別一般比較少用。 容易造成性能上的問(wèn)題窑业。 效率比較低钦幔。
1.6 總結(jié)
分類
- 按效率劃分,從高到低
讀未提交 > 讀已提交 > 可重復(fù)讀 > 可串行化
- 按攔截程度 常柄,從高到底
可串行化 > 可重復(fù)讀 > 讀已提交 > 讀未提交
問(wèn)題
讀未提交
引發(fā)問(wèn)題: 臟讀
讀已提交
解決: 臟讀 鲤氢, 引發(fā): 不可重復(fù)讀
可重復(fù)讀
解決: 臟讀 、 不可重復(fù)讀 西潘, 未解決: 幻讀
可串行化
解決: 臟讀卷玉、 不可重復(fù)讀 、 幻讀喷市。
mySql 默認(rèn)的隔離級(jí)別是 可重復(fù)讀
Oracle 默認(rèn)的隔離級(jí)別是 讀已提交
2. 數(shù)據(jù)庫(kù)連接池
2.1 DBCP
- 導(dǎo)入jar文件
不使用配置文件方式:
public void testDBCP01(){
Connection conn = null;
PreparedStatement ps = null;
try {
//1. 構(gòu)建數(shù)據(jù)源對(duì)象
BasicDataSource dataSource = new BasicDataSource();
//連的是什么類型的數(shù)據(jù)庫(kù)揍庄, 訪問(wèn)的是哪個(gè)數(shù)據(jù)庫(kù) , 用戶名东抹, 密碼蚂子。。
//jdbc:mysql://localhost/bank 主協(xié)議:子協(xié)議 ://本地/數(shù)據(jù)庫(kù)
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost/bank");
dataSource.setUsername("root");
dataSource.setPassword("root");
//2. 得到連接對(duì)象
conn = dataSource.getConnection();
String sql = "insert into account values(null , ? , ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "admin");
ps.setInt(2, 1000);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps);
}
}
使用配置文件方式:
Connection conn = null;
PreparedStatement ps = null;
try {
BasicDataSourceFactory factory = new BasicDataSourceFactory();
Properties properties = new Properties();
InputStream is = new FileInputStream("src//dbcpconfig.properties");
properties.load(is);
DataSource dataSource = factory.createDataSource(properties);
//2. 得到連接對(duì)象
conn = dataSource.getConnection();
String sql = "insert into account values(null , ? , ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "liangchaowei");
ps.setInt(2, 100);
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps);
}
2.2 C3P0
1 .拷貝jar文件 到 lib目錄
不使用配置文件方式
Connection conn = null;
PreparedStatement ps = null;
try {
//1. 創(chuàng)建datasource
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2. 設(shè)置連接數(shù)據(jù)的信息
dataSource.setDriverClass("com.mysql.jdbc.Driver");
//忘記了---> 去以前的代碼 ---> jdbc的文檔
dataSource.setJdbcUrl("jdbc:mysql://localhost/bank");
dataSource.setUser("root");
dataSource.setPassword("root");
//2. 得到連接對(duì)象
conn = dataSource.getConnection();
String sql = "insert into account values(null , ? , ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "admi234n");
ps.setInt(2, 103200);
ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtil.release(conn, ps);
}
使用配置文件方式
//默認(rèn)會(huì)找 xml 中的 default-config 分支缭黔。
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 得到連接對(duì)象
conn = dataSource.getConnection();
String sql = "insert into account values(null , ? , ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, "admi234n");
ps.setInt(2, 103200);
3. DBUtils
3.1 增刪改
//dbutils 只是幫我們簡(jiǎn)化了CRUD 的代碼食茎, 但是連接的創(chuàng)建以及獲取工作。 不在他的考慮范圍
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
//增加
//queryRunner.update("insert into account values (null , ? , ? )", "aa" ,1000);
//刪除
//queryRunner.update("delete from account where id = ?", 5);
//更新
//queryRunner.update("update account set money = ? where id = ?", 10000000 , 6);
3.2 查詢
- 直接new接口的匿名實(shí)現(xiàn)類
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
Account account = queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>(){
@Override
public Account handle(ResultSet rs) throws SQLException {
Account account = new Account();
while(rs.next()){
String name = rs.getString("name");
int money = rs.getInt("money");
account.setName(name);
account.setMoney(money);
}
return account;
}
}, 6);
System.out.println(account.toString());
- 直接使用框架已經(jīng)寫(xiě)好的實(shí)現(xiàn)類馏谨。
* 查詢單個(gè)對(duì)象
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
//查詢單個(gè)對(duì)象
Account account = queryRunner.query("select * from account where id = ?",
new BeanHandler<Account>(Account.class), 8);
* 查詢多個(gè)對(duì)象
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource());
List<Account> list = queryRunner.query("select * from account ",
new BeanListHandler<Account>(Account.class));
3.3 ResultSetHandler 常用的實(shí)現(xiàn)類
以下兩個(gè)是使用頻率最高的
BeanHandler, 查詢到的單個(gè)數(shù)據(jù)封裝成一個(gè)對(duì)象
BeanListHandler, 查詢到的多個(gè)數(shù)據(jù)封裝 成一個(gè)List<對(duì)象>
ArrayHandler, 查詢到的單個(gè)數(shù)據(jù)封裝成一個(gè)數(shù)組
ArrayListHandler, 查詢到的多個(gè)數(shù)據(jù)封裝成一個(gè)集合 别渔,集合里面的元素是數(shù)組。
MapHandler, 查詢到的單個(gè)數(shù)據(jù)封裝成一個(gè)map
MapListHandler,查詢到的多個(gè)數(shù)據(jù)封裝成一個(gè)集合 惧互,集合里面的元素是map哎媚。
ColumnListHandler
KeyedHandler
ScalarHandler