一、闲话
教练,我想打游戏啊!!!!
二、基本要点
1、事务相关回顾
事务的四大特性(ACID)
- 原子性(atomicity):一个事务是一个不可分割的单位,事务中包括的操作要么都做,要么都不做。
- 一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态,与原子性是密切相关。
- 隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响
2、spring中事务管理
主要分为声明式事务:AOP(代码是横切进去的,不影响原有代码逻辑)、编程式事务
1)声明式事务
将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
将事务管理作为横切关注点,通过aop方法模块化。通过Spring AOP框架支持声明式事务管理
假设我们原来的表中有3个人,现在我们要删除掉标号为3的那个,然后假如编号为4的
我们新建一个人员类
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 人员信息
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {
private String userId;
private String name;
private int age;
private String sex;
}
编写接口及实现类,新增、删除和查询接口
package com.decade.mapper;
import com.decade.entity.UserInfo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserInfoDao {
List<UserInfo> queryUserInfo();
void addUserInfo(UserInfo userInfo);
void deleteUserInfo(@Param("id") String id);
}
package com.decade.mapper;
import com.decade.entity.UserInfo;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserInfoDaoImpl extends SqlSessionDaoSupport implements UserInfoDao{
@Override
public List<UserInfo> queryUserInfo() {
UserInfo userInfo = new UserInfo("004", "刘亦菲", 18, "女");
addUserInfo(userInfo);
deleteUserInfo("003");
return getSqlSession().getMapper(UserInfoDao.class).queryUserInfo();
}
@Override
public void addUserInfo(UserInfo userInfo) {
getSqlSession().getMapper(UserInfoDao.class).addUserInfo(userInfo);
}
@Override
public void deleteUserInfo(String id) {
getSqlSession().getMapper(UserInfoDao.class).deleteUserInfo(id);
}
}
编写接口的xml映射文件,这里把删除的sql写错,测试能否成功加入4号删除3号
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.decade.mapper.UserInfoDao">
<select id="queryUserInfo" resultType="com.decade.entity.UserInfo">
select * from t_decade_user;
</select>
<insert id="addUserInfo" parameterType="com.decade.entity.UserInfo">
insert into t_decade_user(id,name,age,sex) values (#{userId},#{name},#{age},#{sex});
</insert>
<delete id="deleteUserInfo" parameterType="java.lang.String">
<!-- 这里把删除的sql写错,测试能否成功加入4号删除3号 -->
deletes from t_decade_user where id = #{id}
</delete>
</mapper>
我们需要导入tx约束,管理数据库连接的配置文件spring-dao2.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 配置数据源,使用spring的数据源替换mybatis, c3p0 druid dbcp -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!--驱动配置,com.mysql.jdbc.driver -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/decade_test?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- 创建sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 绑定mybatis的配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/decade/mapper/*.xml"/>
</bean>
<!--创建sqlSessionTemplate,代替原来的sqlSession -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<!--因为sqlSessionTemplate没有set方法,所以我们使用构造器注入 -->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<!-- 配置声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 结合AOP实现事务的织入 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 需要给哪些字段开头的方法需要配置事务,事务的传播特性,默认为propagation="REQUIRED" -->
<tx:method name="add*" propagation="REQUIRED" read-only="false"/>
<tx:method name="delete*" propagation="REQUIRED" read-only="false"/>
<!-- read-only属性为true时,意思是只有只读权限,无法修改数据库
特殊情况,add方法调用update方法,数据是可以被更新的,因为add的read-only是false
-->
<tx:method name="update*" propagation="REQUIRED" read-only="true"/>
<tx:method name="query*" read-only="false"/>
<!-- 这里的*代表所有方法 -->
<!-- <tx:method name="*"/>-->
</tx:attributes>
</tx:advice>
<!-- 配置事务的织入 -->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.decade.mapper.UserInfoDaoImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
</beans>
下面是mybatis配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.decade.entity"/>
</typeAliases>
</configuration>
和总的spring配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="spring-dao2.xml"/>
<bean id="userDao" class="com.decade.mapper.UserInfoDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
最后编写一个测试类
import com.decade.mapper.UserInfoDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
@org.junit.Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserInfoDao userDao = context.getBean("userDao", UserInfoDao.class);
userDao.queryUserInfo().forEach(System.out::println);
}
}
运行后,我们发现该方法报错,4号未加入,3号未删除,符合预期
2)编程式事务
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
缺点是必须在每个事务操作业务逻辑中包含额外的事务管理代码
在方法出现异常时,调用回滚,我们简单通过一个例子了解一下
public class UserService {
private final PlatformTransactionManager transactionManager;
public UserService(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void createUser() {
TransactionStatus txStatus =
transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
userMapper.insertUser(user);
} catch (Exception e) {
transactionManager.rollback(txStatus);
throw e;
}
transactionManager.commit(txStatus);
}
}
// 在使用 TransactionTemplate 的时候,可以省略对 commit 和 rollback 方法的调用。
public class UserService {
private final PlatformTransactionManager transactionManager;
public UserService(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void createUser() {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(txStatus -> {
userMapper.insertUser(user);
return null;
});
}
}
如有错误,欢迎指正
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/136781.html