framework学习笔记day08---spring基础

37 篇文章 0 订阅
8 篇文章 0 订阅

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’

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
      • 正常获取

AOP对根据类型获取bean的影响总结

  • 有接口

    • image-20211228101251165

    • 使用JDKProxy,放入到Spring容器中的是代理类对象,而代理类实现于UserService接口,和被代理类UserServiceImpl之间没有直接关系

  • 没接口

    • image-20211228101418427

    • 使用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容器,设定了两种不同的事务策略
    • ②改造UserServiceImpl代码
      • 引入事务管理
  • ①编写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

    <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

    <?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";
    }
    
  • 注意事项

    • 操作数据库之前超时,有效;操作数据库之后超时,无效
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值