学习康师傅jdbc课有感而发,分享出来给大家学习。
1.什么叫数据库事务?
事务:一组逻辑操作单元,使数据从一种状态变换到另一种状态。 一组逻辑操作单元:一个或多个DML操作。
2.事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。
当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),那么这些修改就永久地保存下来;要么数据库管理系统将放弃所作的所有修改,整个事务回滚(rollback)到最初状态。
3.数据一旦提交,就不可回滚。
4.哪些操作会导致数据的自动提交?
>DDL操作一旦执行,都会自动提交。
>set autocommit = false 对DDL操作失效
>DML默认情况下,一旦执行,就会自动提交。
>我们可以通过set autocommit = false的方式取消DML操作的自动提交。
>默认在关闭连接时,会自动的提交数据
这个事务的出发点是存在一个银行账户,两个户主进行转帐的问题来开展的。
由于存在如果一个用户转了100块钱给另一个用户,但是另一个用户更新数据之前发生了异常,就会导致钱给了但是另一个用户钱没有增加的情况发生。
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(sql1, "AA");
//模拟网络异常
System.out.println(10 / 0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(sql2, "BB");
这就引发了一个概念叫事务,之后我们需要的是如何对事务进行处理。
public class TransactionTest {
//******************未考虑数据库事务情况下的转账操作**************************
/*
* 针对于数据表user_table来说:
* AA用户给BB用户转账100
*
* update user_table set balance = balance - 100 where user = 'AA';
* update user_table set balance = balance + 100 where user = 'BB';
*/
@Test
public void testUpdate(){
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(sql1, "AA");
//模拟网络异常
System.out.println(10 / 0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(sql2, "BB");
System.out.println("转账成功");
}
// 通用的增删改操作---version 1.0
public int update(String sql, Object... args) {// sql中占位符的个数与可变形参的长度相同!
Connection conn = null;
PreparedStatement ps = null;
try {
// 1.获取数据库的连接
conn = JDBCUtils.getConnection();
// 2.预编译sql语句,返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
// 3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
}
// 4.执行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
//修改其为自动提交数据
//主要针对于使用数据库连接池的使用
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
// 5.资源的关闭
JDBCUtils.closeResource(conn, ps);
}
return 0;
}
由于连接关闭会自动提交数据其次连接DML默认情况下也需要自动提交语句,这就导致了我们需要在连接创建后添加 conn.setAutoCommit(false);为了去取消DML的自动提交,然后需要在增删改的方法函数中取消对数据库连接的关闭操作还有在方法参数中增加连接参数。并修改部分代码逻辑,维持如果声明该方法就只用一个数据库连接。
//********************考虑数据库事务后的转账操作*********************
@Test
public void testUpdateWithTx() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
System.out.println(conn.getAutoCommit());//true
//1.取消数据的自动提交
conn.setAutoCommit(false);
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(conn,sql1, "AA");
//模拟网络异常
System.out.println(10 / 0);
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(conn,sql2, "BB");
System.out.println("转账成功");
//2.提交数据
conn.commit();
} catch (Exception e) {
e.printStackTrace();
//3.回滚数据
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
JDBCUtils.closeResource(conn, null);
}
}
// 通用的增删改操作---version 2.0 (考虑上事务)
public int update(Connection conn,String sql, Object... args) {// sql中占位符的个数与可变形参的长度相同!
PreparedStatement ps = null;
try {
// 1.预编译sql语句,返回PreparedStatement的实例
ps = conn.prepareStatement(sql);
// 2.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);// 小心参数声明错误!!
}
// 3.执行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 4.资源的关闭
JDBCUtils.closeResource(null, ps);
}
return 0;
}
这种处理过后,代码得到了飞跃的提升,也解决了银行用户转账异常的问题。