1.事务的概述
多条sql语句作为一个整体出现,要么都执行,要么都不执行
2.事务的具体案例
1.取消DML语言的自动提交
2.有多个更新命令,防止执行一个命令之后关闭连接自动提交,将在命令外手动开关连接
事务的增删改操作通用模板
// 事务的增删改操作通用模板
// 主要是为了防止关闭连接后自动提交
public void updateTable(Connection conn,String sql,Object...vals){
// 可变形参vals的数量就是占位符的数量
PreparedStatement ps=null;
try {
// 2,实例化PreparedStatement对象
ps=conn.prepareStatement(sql);
// 3.填充占位符
for(int i=0;i<vals.length;i++){
ps.setObject(i+1,vals[i]);
}
// 4.执行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
}finally {
// 5.关闭资源
// conn在方法外打开,也需要在方法外关闭
JDBCUtils.closeResource(null,ps);
}
}
模拟aa给bb转账100元具体操作
public static void main(String[] args) {
Test1 t=new Test1();
Connection conn=null;
try {
conn=JDBCUtils.getConnection();
// 1.取消数据库的自动提交
conn.setAutoCommit(false);
// 模拟aa给bb转账100元
String sql1="update user_table set balance=balance-100 where user=?";
t.updateTable(conn,sql1,"AA");
// 模拟网络异常
// System.out.println(10/0);
String sql2="update user_table set balance=balance+100 where user=?";
t.updateTable(conn,sql2,"BB");
// 2.数据库手动提交
conn.commit();
} catch (Exception e) {
e.printStackTrace();
// 3.出现异常数据库回滚
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}finally{
// 恢复默认状态
// 针对数据库连接池的使用
try {
conn.setAutoCommit(true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
// ps在更新命令中已经关闭
JDBCUtils.closeResource(conn,null);
}
}
3.事务属性和四种事务的隔离级别
不可重复读:更新字段并提交,其他线程在读取结果会有所不同
例如:网上购买商品刷新界面
Mysql默认避免不了幻读,默认可以重复读
Oracle默认避免不了不可重复读和幻读,默认读已经提交
4.事务隔离级别具体实现
Connection conn=JDBCUtils.getConnection();
// 获取当前数据库的隔离级别
// 分别为1,2,4,8,分别对应读未提交,读已提交,可重复读,串行化
System.out.println(conn.getTransactionIsolation());
// 设置数据库的隔离级别
// conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
数据库事务查询代码
// <T>表示这是一个泛型方法,返回类型为T,T类型由实参传入
public <T> T queryTable(Connection conn,Class<T> clazz,String sql,Object...vals){
PreparedStatement ps= null;
ResultSet rs= null;
try {
// 2.预编译sql语句,占位符赋值
ps = conn.prepareStatement(sql);
for(int i=0;i<vals.length;i++){
ps.setObject(i+1,vals[i]);
}
// 3.获取结果集
rs = ps.executeQuery();
ResultSetMetaData rsmd=rs.getMetaData();
int columnCount=rsmd.getColumnCount();
// 4,生成返回的结果集对象
if(rs.next()){
// 通过声明的构造器,new一个T类型的对象
T t=clazz.getDeclaredConstructor().newInstance();
for(int i=0;i<columnCount;i++){
Object columnVal=rs.getObject(i+1);
String columnLabel=rsmd.getColumnLabel(i+1);
// 反射为对象属性赋值
Field field=t.getClass().getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnVal);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
// 5.关闭资源连接
JDBCUtils.closeResource(null,ps,rs);
}
return null;
}