事务:
-
定义:
- 一个事务通常对应着一个业务,同时事务不可再分,最小工作单元
- 一个完整的业务需要批量的 DML(insert、update、delete) 语句共同联合完成
- 事务只和 DML 语句相关,或者说语句才有事务。这个和业务逻辑相关,业务逻辑不同,DML 语句数量也会不相同
-
事务的四大特性:
- 原子性:一个事务是一个不可分割的工作单元
- 一致性:事务在执行前和执行后,数据库的状态必须保持一致。这意味着事务执行过程中的任何变化都必须满足预定的规则和约束
- 隔离性:事务和事务之间是相互隔离的,各个事务之间不能相互干扰
- 持久性:事务一旦提交,数据将永久保存在数据库中
-
提交数据:
- 非事务提交:
#非事务提交 update user set money = money + 100 where name = '张三'; update user set money = money - 100 where name = '李四';
- 事务提交:
- start transaction:开启事务
- commit:提交事务
- rollback:当事务提交之后回滚事务,回滚是不生效的因为事务提交之后,事务的持久性就会起作用
#事务提交 start transaction; //开启事务 update user set money = money + 100 where name = '张三'; update user set money = money - 100 where name = '李四'; commit; //提交事务
- 事务隔离级别产生的问题:
- 脏读:事务 A 读取到了 事务 B 修改后未提交的数据
- 不可重复读:在一个事务内,多次读取同一数据,但是数据的值发生了改变 (针对的是 update 语句)
- 虚读(幻读):在一个事务中,多次查询同一个范围的数据,却发现有新增或减少的行(针对的是 insert 语句)
- 这是因为在这个事务进行的过程中,另一个事务插入或删除了符合条件查询的数据,导致前后两次查询结果不一致
- 这是因为在这个事务进行的过程中,另一个事务插入或删除了符合条件查询的数据,导致前后两次查询结果不一致
- 事务隔离级别:
- Read uncommitted:什么都不预防
- Read committed:避免脏读,但是不可重复读有可能产生
- serializable:串行化
- 非事务提交:
MyBatis 事务管理
-
编写配置:
<environments default="mysql"> <environment id="mysql"> <!--配置事务的类型,使用本地事务策略--> <transactionManager type="JDBC"></transactionManager> <!--是否使用连接池 POOLED表示使用链接池,UNPOOLED表示不使用连接池--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo?useUnicode=true&characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments>
-
连接数据库:
private InputStream in = null; private SqlSession session = null; private UserDao mapper = null; @Before //前置通知, 在方法执行之前执行 public void init() throws IOException { //加载主配置文件,目的是为了构建SqlSessionFactory对象 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //创建SqlSessionFactory对象 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in); //通过SqlSessionFactory工厂对象创建SqlSesssion对象 session = factory.openSession(); //通过Session创建UserDao接口代理对象 mapper = session.getMapper(UserDao.class); } @After //@After: 后置通知, 在方法执行之后执行 。 public void destory() throws IOException { //释放资源 session.close(); in.close(); }
-
事务回滚:
//事务回滚 @Test public void insert(){ try{ //事务操作 }catch (Exception e){ session.rollback(); //事务回滚 }finally { if(session != null){ session.close(); } } }