AOP注解开发
-
开发步骤
- ①开启支持AOP注解
- ②制作目标对象类
- ③制作通知类
- 使用AOP注解
-
①开启支持AOP注解
<?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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.atguigu"></context:component-scan> <!--开启AOP注解支持--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
-
②制作目标对象类
@Service public class UserServiceImpl implements UserService { @Override public void addUser() throws Exception { System.out.println("UserServiceImpl addUser"); System.out.println(1 / 0); } @Override public void deleteUser() throws Exception { System.out.println("UserServiceImpl deleteUser"); } }
-
③制作通知类
@Aspect @Component public class MyAdvice01 { @Before("execution(* *..*Service.addUser())") public void before(){ System.out.println("MyAdvice01 before"); } @AfterReturning("execution(* *..*Service.addUser())") public void afterReturning(){ System.out.println("MyAdvice01 afterReturning"); } @AfterThrowing("execution(* *..*Service.addUser())") public void afterThrowing(){ System.out.println("MyAdvice01 afterThrowing"); } @After("execution(* *..*Service.addUser())") public void after(){ System.out.println("MyAdvice01 after"); } @Around("execution(* *..*Service.addUser())") public void around(ProceedingJoinPoint pjp){ System.out.println("MyAdvice01 around之前"); try { pjp.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("MyAdvice01 around之后"); } }
AOP注解获取切入点输入参数
-
分类
- around通知获取
- 非around通知获取
-
代码实现
@Aspect @Component public class MyAdvice02 { @Around("execution(* *..*Service.*(..))") public void around(ProceedingJoinPoint pjp) { Object[] args = pjp.getArgs(); System.out.println("MyAdvice02 around" + Arrays.toString(args)); try { pjp.proceed(); } catch (Throwable e) { e.printStackTrace(); } } @Before("execution(* *..*Service.*(..))") public void before(JoinPoint jp){ Object[] args = jp.getArgs(); System.out.println("MyAdvice02 before" + Arrays.toString(args)); } }
AOP注解获取切入点返回值
-
概述
- after-returning、around可以获取切入点返回值
-
代码实现
@Aspect @Component public class MyAdvice03 { @Around("execution(* *..*Service.*(..))") public Object around(ProceedingJoinPoint pjp) { try { Object result = pjp.proceed(); System.out.println("MyAdvice03 around " + result); return result; } catch (Throwable e) { e.printStackTrace(); } return null; } @AfterReturning(value = "execution(* *..*Service.*(..))",returning = "result") public void afterReturning(Object result){ System.out.println("MyAdvice03 afterReturning " + result); } }
AOP注解获取切入点异常
-
概述
- after-throwing、around可以获取切入点的异常
-
代码实现
@Aspect @Component public class MyAdvice04 { @Around("execution(* *..*Service.*(..))") public void around(ProceedingJoinPoint pjp) { try { pjp.proceed(); } catch (Throwable e) { e.printStackTrace(); System.out.println("MyAdvice04 around " + e); throw new RuntimeException(e); } } @AfterThrowing(value = "execution(* *..*Service.*(..))" , throwing = "e") public void afterThrowing(Exception e){ System.out.println("MyAdvice04 afterThrowing " + e); } }
AOP对根据类型获取bean的影响场景一
-
需求
- 声明一个接口,接口有一个实现子类
- 创建一个通知类,对上面接口的实现子类应用通知
- 根据接口类型获取bean
- 根据实现子类类型获取bean
-
总结
- 根据接口类型获取bean
- 正常获取
- 根据实现子类类型获取bean
- 报错,BeanNotOfRequiredTypeException: Bean named ‘userServiceImpl’ is expected to be of type ‘com.atguigu.service.impl.UserServiceImpl’ but was actually of type ‘com.sun.proxy.$Proxy20’
- 根据接口类型获取bean
AOP对根据类型获取bean的影响场景二
-
需求
- 声明一个类
- 创建一个通知类,对上面的类应用通知
- 根据这个类的类型获取bean
-
代码实现
@Service public class UserServiceImpl2 { public String addUser(int num) throws Exception { System.out.println("UserServiceImpl2 addUser " + num); //System.out.println(1 / 0); return "helloworld"; } public void deleteUser() throws Exception { System.out.println("UserServiceImpl2 deleteUser"); } }
@Aspect @Component public class MyAdvice06 { @Before("execution(* *..UserServiceImpl2.*(..))") public void before(){ System.out.println("MyAdvice06 before"); } }
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring-core.xml") public class UserServiceImpl2Test { @Autowired private UserServiceImpl2 userServiceImpl2; @Test public void addUser() throws Exception { userServiceImpl2.addUser(250); } @Test public void deleteUser() { } }
-
总结
- 根据这个类的类型获取bean
- 正常获取
- 根据这个类的类型获取bean
AOP对根据类型获取bean的影响总结
-
有接口
-
-
使用JDKProxy,放入到Spring容器中的是代理类对象,而代理类实现于UserService接口,和被代理类UserServiceImpl之间没有直接关系
-
-
没接口
-
-
使用CGLIB,放入到Spring容器中的是代理类对象,而代理类继承于UserServiceImpl(被代理类),也就是说,代理类和被代理类之间是继承关系
-
JdbcTemplate模板类使用
-
开发步骤
- ①引入相关依赖
- spring-jdbc
- ②定义dao接口及其实现子类
- ③编写spring-core.xml
- 将JdbcTemplate对象放入Spring容器
- ④代码测试
- ①引入相关依赖
-
①引入相关依赖
<properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <junit.version>4.13.2</junit.version> <lombok.version>1.18.22</lombok.version> <spring.version>5.3.13</spring.version> <dbutils.version>1.7</dbutils.version> <druid.version>1.2.8</druid.version> <mysql.version>5.1.48</mysql.version> </properties> <dependencies> <!--junit start--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!--junit end--> <!--lombok start--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <!--lombok end--> <!--spring start--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jcl</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.7</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!--spring end--> <!--jdbc start--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!--jdbc end--> </dependencies>
-
②定义dao接口及其实现子类
@Repository public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void addUser(User inputUser) throws Exception { jdbcTemplate.update( "insert into tb_user values(null,?,?,?)", inputUser.getUserName(), inputUser.getUserPwd(), inputUser.getMoney() ); } @Override public void deleteUser(Integer userId) throws Exception { jdbcTemplate.update( "delete from tb_user where user_id = ?", userId ); } @Override public void updateUser(User inputUser) throws Exception { jdbcTemplate.update( "update tb_user set user_name = ? , user_pwd = ? , money = ? where user_id = ?", inputUser.getUserName(), inputUser.getUserPwd(), inputUser.getMoney(), inputUser.getUserId() ); } @Override public User selectUserById(Integer userId) throws Exception { String sql = "select * from tb_user where user_id = ?"; RowMapper<? extends User> rowMapper = new RowMapper<User>() { @Override public User mapRow(ResultSet resultSet, int i) throws SQLException { User user = new User(); user.setUserId(resultSet.getInt("user_id")); user.setUserName(resultSet.getString("user_name")); user.setUserPwd(resultSet.getString("user_pwd")); user.setMoney(resultSet.getDouble("money")); return user; } }; return jdbcTemplate.queryForObject( sql, rowMapper, userId ); } @Override public List<User> selectUserList() throws Exception { return jdbcTemplate.query( "select user_id userId,user_name userName , user_pwd userPwd ,money money from tb_user", new BeanPropertyRowMapper<>(User.class) ); } }
-
③编写spring-core.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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.atguigu"></context:component-scan> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <context:property-placeholder location="jdbc.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClass}"></property> <property name="url" value="${url}"></property> <property name="username" value="${user}"></property> <property name="password" value="${password}"></property> </bean> </beans>
-
④代码测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring-core.xml") public class UserDaoTest { @Autowired private UserDao userDao; @Test public void addUser() throws Exception { userDao.addUser(new User(1,"zhangsan","zhangsan",10000.0)); } @Test public void deleteUser() { } @Test public void updateUser() { } @Test public void selectUserById() throws Exception { User user = userDao.selectUserById(52); System.out.println("user = " + user); } @Test public void selectUserList() throws Exception { List<User> userList = userDao.selectUserList(); System.out.println("userList = " + userList); } }
Spring事务概念
- 分类
- 编程式事务(难点)
- 使用PlatformTransactionManager
- 开发人员自己写java代码实现事务管理,是Spring事务管理原理
- 声明式事务
- XML配置声明
- 注解配置声明
- 编程式事务(难点)
- 核心类
- PlatformTransactionManager : 事务管理类
- TransactionDefinition : 事务信息配置类
- TransactionStatus : 事务状态类
PlatformTransactionManager接口概述
- 概述
- 提供常用的操作事务的方法
- 常用方法
- getTransaction : 开启事务
- commit : 提交事务
- rollback : 回滚事务
- 实现子类
- DataSourceTransactionManager : 适用于Spring JDBC或mybatis
- HibernateTransactionManager : 适用于hibernate
- JpaTransactionManager : 适用于Spring Data JPA
TransactionDefinition接口概述
- 概述
- 此接口定义了事务的属性(隔离级别、传播行为、超时、只读性)
- 常用方法
- 设置/获取隔离级别
- getIsolationLevel/setIsolationLevel
- 设置/获取传播行为
- getPropagationBehavior/setPropagationBehavior
- 设置/获取只读性
- setReadOnly/isReadOnly
- 设置/获取超时
- setTimeout/getTimeout
- 设置/获取隔离级别
- 继承结构
- DefaultTransactionDefinition
TransactionStatus接口概述
- 概述
- 封装了事务的状态信息(是否是一个新的事务、是否已经结束等等)
- 继承结构
- DefaultTransactionStatus
Spring事务管理环境搭建
-
需求
- 转账业务(zhangsan向lisi转账100元)
-
开发步骤
- ①定义service及其实现子类
- ②定义dao及其实现子类
- ③代码测试
-
①定义service及其实现子类
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void transfer(String outName, String inName, Double money) throws Exception { //出账 userDao.outMoney(outName, money); System.out.println(1 / 0); //入账 userDao.inMoney(inName, money); } }
-
②定义dao及其实现子类
@Repository public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public void outMoney(String outName, Double money) throws Exception { jdbcTemplate.update( "update tb_user set money = money - ? where user_name = ?", money, outName ); } @Override public void inMoney(String inName, Double money) throws Exception { jdbcTemplate.update( "update tb_user set money = money + ? where user_name = ?", money, inName ); } }
-
③代码测试
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:spring-core.xml") public class UserServiceTest { @Autowired private UserServiceImpl userService; @Test public void transfer() throws Exception { userService.transfer("zhangsan", "lisi", 100.0); } }
Spring编程式事务基础版
-
概述
- 使用DataSourceTransactionManager进行事务管理
-
开发步骤
- ①编写spring-core.xml
- 1.1,将DataSourceTransactionManager对象放入到Spring容器
- 注入dataSource
- 1.2,将DefaultTransactionDefinition对象放入到Spring容器,设定了两种不同的事务策略
- 1.1,将DataSourceTransactionManager对象放入到Spring容器
- ②改造UserServiceImpl代码
- 引入事务管理
- ①编写spring-core.xml
-
①编写spring-core.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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> //.... <!--1.1,将DataSourceTransactionManager对象放入到Spring容器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--1.2,将DefaultTransactionDefinition对象放入到Spring容器,设定了两种不同的事务策略--> <!--TransactionDefinition : 只读性=false,隔离级别=REPEATABLE_READ--> <bean id="definition1" class="org.springframework.transaction.support.DefaultTransactionDefinition"> <property name="readOnly" value="false"></property> </bean> <!--TransactionDefinition : 只读性=true,隔离级别=REPEATABLE_READ--> <bean id="definition2" class="org.springframework.transaction.support.DefaultTransactionDefinition"> <property name="readOnly" value="true"></property> </bean> </beans>
-
②改造UserServiceImpl代码
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Autowired private DataSourceTransactionManager transactionManager; @Autowired @Qualifier("definition1") private TransactionDefinition definition; @Override public void transfer(String outName, String inName, Double money) throws Exception { TransactionStatus status = null; try { //开启事务 status = transactionManager.getTransaction(definition); //出账 userDao.outMoney(outName, money); System.out.println(1 / 0); //入账 userDao.inMoney(inName, money); //没有异常就提交事务 transactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); //有异常就回滚事务 transactionManager.rollback(status); } } }
-
存在问题
- 事务管理代码会被大量的使用,会有重复冗余问题。
Spring编程式事务优化版
-
概述
- 使用MyTransactionManager工具类(开启事务、提交事务、回滚事务)
-
开发步骤
- ①自定义MyTransactionManager工具类
- ②改造UserServiceImpl代码
- 使用MyTransactionManager工具类
-
①自定义MyTransactionManager工具类
@Component public class MyTransactionManager { @Autowired private DataSourceTransactionManager transactionManager; @Autowired @Qualifier("definition1") private DefaultTransactionDefinition definition; /** * 开启事务 */ public TransactionStatus startTransaction(){ TransactionStatus status = transactionManager.getTransaction(definition); return status; } /** * 提交事务 * @param status */ public void commit(TransactionStatus status){ transactionManager.commit(status); } /** * 回滚事务 * @param status */ public void rollback(TransactionStatus status){ transactionManager.rollback(status); } }
-
②改造UserServiceImpl代码
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Autowired private MyTransactionManager transactionManager; @Override public String addUser(int num) throws Exception { System.out.println("UserServiceImpl addUser " + num); //System.out.println(1 / 0); return "helloworld"; } @Override public void deleteUser() throws Exception { try { System.out.println("UserServiceImpl deleteUser"); } catch (Exception e) { e.printStackTrace(); } } @Override public void transfer(String outName, String inName, Double money) throws Exception { TransactionStatus status = null; try { //开启事务 status = transactionManager.startTransaction(); //出账 userDao.outMoney(outName, money); //System.out.println(1 / 0); //入账 userDao.inMoney(inName, money); //没有异常就提交事务 transactionManager.commit(status); } catch (Exception e) { e.printStackTrace(); //有异常就回滚事务 transactionManager.rollback(status); } } }
-
存在问题
- ①UserServiceImpl主要功能是增删改查,辅助功能是事务管理,也就是说事务管理属于增强功能,可以使用AOP通知;
- ②假设UserServiceImpl中有100个方法都需要进行事务管理,意味着事务管理属于共性功能,可以使用AOP通知。
Spring编程式事务最终版
-
概述
- 使用环绕通知解决事务管理代码增强功能。
-
开发步骤
- ①定义事务通知类TxAdvice
- ②编写spring-core.xml
- 配置AOP通知
-
①定义事务通知类TxAdvice
@Component public class TxAdvice { @Autowired private MyTransactionManager transactionManager; @Autowired @Qualifier("definition1") private TransactionDefinition definition1; /** * DML的事务通知 * @param pjp */ public void dmlAround(ProceedingJoinPoint pjp) { TransactionStatus status = null; //开启事务 try { status = transactionManager.startTransaction(definition1); pjp.proceed(); transactionManager.commit(status); } catch (Throwable e) { e.printStackTrace(); transactionManager.rollback(status); } } @Autowired @Qualifier("definition2") private TransactionDefinition definition2; /** * DQL的事务通知 * @param pjp */ public void dqlAround(ProceedingJoinPoint pjp){ TransactionStatus status = null; //开启事务 try { status = transactionManager.startTransaction(definition2); pjp.proceed(); transactionManager.commit(status); } catch (Throwable e) { e.printStackTrace(); transactionManager.rollback(status); } } }
-
②编写spring-core.xml
<!--DataSourceTransactionManager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--TransactionDefinition : 只读性=false,隔离级别=REPEATABLE_READ--> <bean id="definition1" class="org.springframework.transaction.support.DefaultTransactionDefinition"> <property name="readOnly" value="false"></property> </bean> <!--TransactionDefinition : 只读性=true,隔离级别=REPEATABLE_READ--> <bean id="definition2" class="org.springframework.transaction.support.DefaultTransactionDefinition"> <property name="readOnly" value="true"></property> </bean> <aop:config> <aop:aspect ref="txAdvice"> <aop:around method="dmlAround" pointcut="execution(* *..*Service.transfer(..))"></aop:around> <aop:around method="dmlAround" pointcut="execution(* *..*Service.deleteUser(..))"></aop:around> <aop:around method="dmlAround" pointcut="execution(* *..*Service.addUser(..))"></aop:around> <aop:around method="dqlAround" pointcut="execution(* *..*Service.selectUser(..))"></aop:around> </aop:aspect> </aop:config>
声明式事务概述
- 概述
- 将编程式事务中的通用代码抽取出来,制作成独立的around通知使用AOP工作原理,将事 务管理的代码动态织入到原始方法中。由于该功能使用量较大,Spring已经将该通知制作完 毕。
- 开发人员只需要通过xml配置或注解配置的方式进行使用即可
- 分类
- xml声明式事务
- 注解声明式事务
xml声明式事务
-
开发步骤
- ①编写spring-core.xml
- 配置tx:advice
- 将tx:advice作用到对应的切入点
- ①编写spring-core.xml
-
①编写spring-core.xml
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" read-only="false"/> <tx:method name="selectUserList" read-only="true"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* *..*Service.*(..))"></aop:advisor> </aop:config>
xml声明式事务属性配置
-
常用属性
- read-only : 只读事务
- isolation : 事务隔离级别
- timeout : 事务超时属性
- rollback-for : 指定异常需要回滚
- no-rollback-for : 指定异常不需要回滚
-
代码实现
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" read-only="false" isolation="REPEATABLE_READ" timeout="10" propagation="REQUIRED" /> <tx:method name="select*" read-only="true" isolation="REPEATABLE_READ" timeout="10" propagation="REQUIRED"/> <tx:method name="add*" read-only="false" isolation="REPEATABLE_READ" timeout="10" propagation="REQUIRED"/> <tx:method name="delete*" read-only="false" isolation="REPEATABLE_READ" timeout="10" propagation="REQUIRED"/> <tx:method name="update*" read-only="false" isolation="REPEATABLE_READ" timeout="10" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* *..*Service.*(..))"></aop:advisor> </aop:config>
注解声明式事务
-
开发步骤
- ①编写spring-core.xml
- 开启事务注解支持
- ②改造UserServiceImpl
- 使用事务注解
- ①编写spring-core.xml
-
①编写spring-core.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:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--注解声明式事务--> <context:component-scan base-package="com.atguigu"></context:component-scan> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <context:property-placeholder location="jdbc.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClass}"></property> <property name="url" value="${url}"></property> <property name="username" value="${user}"></property> <property name="password" value="${password}"></property> </bean> <!--DataSourceTransactionManager--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--开启事务注解支持--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans>
-
②改造UserServiceImpl
@Transactional(readOnly = false, isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED, timeout = 10) @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Transactional(readOnly = true) @Override public List<User> selectUserList() throws Exception { return userDao.selectUserList(); } @Override public String addUser(int num) throws Exception { System.out.println("UserServiceImpl addUser " + num); //System.out.println(1 / 0); return "helloworld"; } @Override public void deleteUser() throws Exception { System.out.println("UserServiceImpl deleteUser"); } @Override public void transfer(String outName, String inName, Double money) throws Exception { userDao.outMoney(outName, money); System.out.println(1 / 0); userDao.inMoney(inName, money); } }
事务的readOnly属性
-
概述
- 对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及 写操作。这样数据库就能够针对查询操作来进行优化。
-
代码实现
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Transactional(readOnly = true) @Override public List<User> selectUserList() throws Exception { return userDao.selectUserList(); } @Transactional(readOnly = false) @Override public String addUser(User inputUser) throws Exception { //System.out.println(1 / 0); userDao.addUser(inputUser); return "helloworld"; } @Override public void deleteUser() throws Exception { System.out.println("UserServiceImpl deleteUser"); } @Override public void transfer(String outName, String inName, Double money) throws Exception { userDao.outMoney(outName, money); System.out.println(1 / 0); userDao.inMoney(inName, money); } }
-
注意事项
- DML操作的readOnly必须是false,否则报错"Connection is read-only"
事务的timeout属性
-
概述
- 事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资 源。而长时间占用资源,大概率是因为程序运行出现了问题
- 此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来, 让其他正常程序可以执行。
-
代码实现
@Transactional(readOnly = false,timeout = 5) @Override public String addUser(User inputUser) throws Exception { //操作数据库之前超时,有效 Thread.sleep(6000); userDao.addUser(inputUser); //操作数据库之后超时,无效 //Thread.sleep(6000); return "helloworld"; }
-
注意事项
userDao.selectUserList();
}@Transactional(readOnly = false) @Override public String addUser(User inputUser) throws Exception { //System.out.println(1 / 0); userDao.addUser(inputUser); return "helloworld"; } @Override public void deleteUser() throws Exception { System.out.println("UserServiceImpl deleteUser"); } @Override public void transfer(String outName, String inName, Double money) throws Exception { userDao.outMoney(outName, money); System.out.println(1 / 0); userDao.inMoney(inName, money); }
}
-
注意事项
- DML操作的readOnly必须是false,否则报错"Connection is read-only"
事务的timeout属性
-
概述
- 事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资 源。而长时间占用资源,大概率是因为程序运行出现了问题
- 此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来, 让其他正常程序可以执行。
-
代码实现
@Transactional(readOnly = false,timeout = 5) @Override public String addUser(User inputUser) throws Exception { //操作数据库之前超时,有效 Thread.sleep(6000); userDao.addUser(inputUser); //操作数据库之后超时,无效 //Thread.sleep(6000); return "helloworld"; }
-
注意事项
- 操作数据库之前超时,有效;操作数据库之后超时,无效