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

framework学习笔记day08---spring基础,第1张

framework学习笔记day08---spring基础 AOP注解开发
  • 开发步骤

    • ①开启支持AOP注解
    • ②制作目标对象类
    • ③制作通知类
      • 使用AOP注解
  • ①开启支持AOP注解

    
    
        
        
        
    
    
  • ②制作目标对象类

    @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的影响总结
  • 有接口

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

  • 没接口

    • 使用CGLIB,放入到Spring容器中的是代理类对象,而代理类继承于UserServiceImpl(被代理类),也就是说,代理类和被代理类之间是继承关系

JdbcTemplate模板类使用
  • 开发步骤

    • ①引入相关依赖
      • spring-jdbc
    • ②定义dao接口及其实现子类
    • ③编写spring-core.xml
      • 将JdbcTemplate对象放入Spring容器
    • ④代码测试
  • ①引入相关依赖

    
        8
        8
        4.13.2
        1.18.22
        5.3.13
        1.7
        1.2.8
        5.1.48
    
    
    
    
        
        
            junit
            junit
            ${junit.version}
            test
        
        
    
        
        
            org.projectlombok
            lombok
            ${lombok.version}
        
        
    
        
        
            org.springframework
            spring-core
            ${spring.version}
        
        
            org.springframework
            spring-beans
            ${spring.version}
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-expression
            ${spring.version}
        
    
        
            org.springframework
            spring-test
            ${spring.version}
        
    
        
            org.springframework
            spring-jcl
            ${spring.version}
        
    
        
            org.springframework
            spring-aop
            ${spring.version}
        
    
        
            org.springframework
            spring-aspects
            ${spring.version}
        
    
        
            org.aspectj
            aspectjweaver
            1.9.7
        
    
        
            aopalliance
            aopalliance
            1.0
        
        
            org.springframework
            spring-jdbc
            ${spring.version}
        
        
    
        
        
            com.alibaba
            druid
            ${druid.version}
        
        
            mysql
            mysql-connector-java
            ${mysql.version}
        
        
    
    
    
  • ②定义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 rowMapper = new RowMapper() {
                @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 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

    
    
    
    
        
    
        
            
        
        
        
            
            
            
            
        
    
    
    
  • 代码测试

    @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 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

    
    
    
        //....
    
        
        
            
        
    
        
        
        
            
        
    
        
        
            
        
    
    
    
  • ②改造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;
        }
    
    
        
        public void commit(TransactionStatus status){
            transactionManager.commit(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;
    
    
        
        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;
    
        
        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

    
        
    
    
    
    
        
    
    
    
    
        
    
    
    
    
        
            
            
            
            
        
    
    
声明式事务概述
  • 概述
    • 将编程式事务中的通用代码抽取出来,制作成独立的around通知使用AOP工作原理,将事 务管理的代码动态织入到原始方法中。由于该功能使用量较大,Spring已经将该通知制作完 毕。
    • 开发人员只需要通过xml配置或注解配置的方式进行使用即可
  • 分类
    • xml声明式事务
    • 注解声明式事务
xml声明式事务
  • 开发步骤

    • ①编写spring-core.xml
      • 配置tx:advice
      • 将tx:advice作用到对应的切入点
  • ①编写spring-core.xml

    
        
            
            
        
    
    
    
        
    
    
xml声明式事务属性配置
  • 常用属性

    • read-only : 只读事务
    • isolation : 事务隔离级别
    • timeout : 事务超时属性
    • rollback-for : 指定异常需要回滚
    • no-rollback-for : 指定异常不需要回滚
  • 代码实现

    
        
            
            
            
            
            
        
    
    
    
        
    
    
注解声明式事务
  • 开发步骤

    • ①编写spring-core.xml
      • 开启事务注解支持
    • ②改造UserServiceImpl
      • 使用事务注解
  • ①编写spring-core.xml

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

    • *** 作数据库之前超时,有效; *** 作数据库之后超时,无效

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5684186.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存