spring中的事务管理
1.什么是事务
一组业务看整一个业务,要么都成功,要么都失败
事务在项目开发中,涉及到数据一致性的问题
确保完整性,一致性
事务的ACID原则:
原子性
一致性
隔离性:多个业务操作一个资源,防止数据算坏
持久性:事务一旦提交,无论发生什么,数据结果不会再次改变,持久化的写在存储器里面。
2.代码实现
先做一个整合了mybatis的spring项目
然后导入一个delete方法
package com.yu.mapper;
import com.yu.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserMapper {
public List<User> selectUser();
//添加一个用户
public int addUser(User user);
//删除一个用户
public int deleteUser(
同时在xml中注册一个delete和add的方法(注意这里的delete注册是错误的,下面的SQL语句多了一个s)
<delete id="deleteUser" parameterType="int">
deletes from mybatis.user where id=#{id}
</delete>
<insert id="addUser" parameterType="user">
insert into mybatis.user(id,name,password) value(#{id},#{name},#{password});
</insert>
在impl中也要加入相对应的实现类,同时在adduser中也加入delete的功能,代码如下:
package com.yu.mapper;
import com.yu.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
public List<User> selectUser() {
User user = new User ( 5, "小王", "2131231" );
UserMapper mapper =getSqlSession ().getMapper ( UserMapper.class);
mapper.addUser (user);
mapper.deleteUser ( 5 );
return getSqlSession ().getMapper ( UserMapper.class ).selectUser ();
}
public int addUser(User user) {
return getSqlSession ().getMapper ( UserMapper.class ).addUser (user);
}
public int deleteUser(int id) {
return getSqlSession ().getMapper ( UserMapper.class ).deleteUser ( id );
}
}
·这时候通过测试类打印出来结果,测试类代码如下:
import com.yu.mapper.UserMapper;
import com.yu.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext ( "applicationContext.xml" );
UserMapper userMapper = context.getBean ( "userMapper" , UserMapper.class );
List<User> userList = userMapper.selectUser ();
for (User user : userList) {
System.out.println (user);
}
}
}
预想结果:报错,添加用户和删除用户两个方法都不执行
实际结果:不出意外,delete方法报错了
数据却插入进了数据库中,违反了一致性的原则
查看官方文档:
官网说的很明确,用 Spring 中的 DataSourceTransactionManager 来实现事务管理。
2.什么是事务
声明式事务(交由容器事务):AOP
编程式事务:需要再代码中,进行事务管理
根据官方文档,现在xml配置文件中,开启声明式事务
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
然后配置好事务
官方的是直接给一个方法,然后把事务配置到方法上。我们一般选择横切的方式(结合AOP,也能更好地理接AOP)
<!--结合aop实现事务的织入-->
<!--配置事务得类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--配置事务的穿鼻特性:new propagation(传播) 默认是REQUIRED-->
<!--query,设置成只读,true,则这个方法不能对数据库进行增删改-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED" />
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.yu.mapper.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
最后的一个 <tx:method name="*" propagation="REQUIRED"/>代表所有方法都使用事务
注:七种事务配置(在propagation后面等号就能看到,一般使用REQUIRED,也是Spring默认的方式)
REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
配置完事务后,程序报错,同时不执行增加的方法
为什么要配置事务?
如果不配置,可能存在数据提交不一致的情况;
如果不在spring去配置声明式事务,我们就需要在代码中手动配置事务
事务在项目开发中十分重要,涉及到数据的一致性和完整性。