05.注解事务

半注解、注解AOP、注解事务、全注解

一、半注解

use-default-filters:使用默认过滤规则,默认(true)引入所有的组件
<context:include-filter>:指定引入规则
type:规则判断依据
annotation
expression:被引入的内容的表达式
org.springframework.stereotype.Controller
<context:exclude-filter>:指定排除规则(有引入的内容)
type:规则判断依据
annotation
expression:被排除的内容的表达式
org.springframework.stereotype.Controller

案例:
配置文件
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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 测试半注解 开启注解扫描 -->
    <context:component-scan base-package="com.yl"/>
    
    <context:component-scan base-package="com.yl" use-default-filters="true">
        <!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
        <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
    </context:component-scan>
    <!--
        @Primary:设置主要的继承类,当需要注入父类类型的时候,并且父类是抽象类的时候,则默认取其主要的子类作为注入的数据
        设置扫描德过滤规则
    -->
</beans>
UserInfo.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
 * 用户的实体类
 */
@Component
public class UserInfo {
    private Integer userId;
    @Value("张胜男")
    private String userName;
    private Date createTime;
    private String userAddress;
    private String userEmail;
    public UserInfo(Integer userId, String userName, Date createTime, String userAddress, String userEmail) {
        this.userId = userId;
        this.userName = userName;
        this.createTime = createTime;
        this.userAddress = userAddress;
        this.userEmail = userEmail;
    }
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public String getUserAddress() {
        return userAddress;
    }
    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }
    public String getUserEmail() {
        return userEmail;
    }
    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }
    @Override
    public String toString() {
        return "UserInfo{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", createTime=" + createTime +
                ", userAddress='" + userAddress + '\'' +
                ", userEmail='" + userEmail + '\'' +
                '}';
    }
}
测试
public void testUserInfo(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        /*String[] beanNames = context.getBeanDefinitionNames();
        // getBeanDefinitionNames 获取所有的
        for(String beanName : beanNames){
            System.out.println(beanName);
        }
        */
        UserInfo userInfo = context.getBean("userInfo", UserInfo.class);

        System.out.println(userInfo);
        System.out.println(userInfo.getPet().getClass());
    }
抽象类注解案例(多个实现类):
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public abstract class Pet {
    private Integer petId;
    @Value("旺财")
    private String petName;
    private String petSex;
    public Pet() {
    }
    public Pet(Integer petId, String petName, String petSex) {
        this.petId = petId;
        this.petName = petName;
        this.petSex = petSex;
    }
    @Override
    public String toString() {
        return "Pet{" +
                "petId=" + petId +
                ", petName='" + petName + '\'' +
                ", petSex='" + petSex + '\'' +
                '}';
    }
    public Integer getPetId() {
        return petId;
    }
    public void setPetId(Integer petId) {
        this.petId = petId;
    }
    public String getPetName() {
        return petName;
    }
    public void setPetName(String petName) {
        this.petName = petName;
    }
    public String getPetSex() {
        return petSex;
    }
    public void setPetSex(String petSex) {
        this.petSex = petSex;
    }
}
cat.java 实现类
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy // 是否懒加载
public class Cat extends Pet {
    private String catType;
    public String getCatType() {
        return catType;
    }
    public void setCatType(String catType) {
        this.catType = catType;
    }
    public void zhuaLaoShu(){
        System.out.println("抓老鼠!");
    }
}
dog.java 实现类
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Primary // 当有多个实现类的时候,默认以该类为启动项
@Scope(value = "prototype") // 是否单列
public class Dog extends Pet {
    private Integer height;
    public void kanJia(){
        System.out.println("狗看门!");
    }
}
配置文件
<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 测试半注解 开启注解扫描 -->
    <context:component-scan base-package="com.yl"/>

    <context:component-scan base-package="com.yl" use-default-filters="true">
        <!--<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
        <!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->
    </context:component-scan>
    <!--
        @Primary:设置主要的继承类,当需要注入父类类型的时候,并且父类是抽象类的时候,则默认取其主要的子类作为注入的数据
        设置扫描德过滤规则
    -->
</beans>

二、注解AOP

案例:
calc.java
import org.springframework.stereotype.Component;
// 被通知类
@Component
public class Calc {
    public Integer cheng(int num1,int num2){
        return num1*num2;
    }
    public Integer chu(int num1,int num2){
        return num1/num2;
    }
}
MyAspect.java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
// 通知类
@Component
@Aspect
public class MyAspect {
    // 切点
    @Pointcut(value = "execution(* com.yl.entity.Calc.*(..))")
    public void pointdemo(){}
    // 前置通知
    @Before("pointdemo()")
    public void before(){
        System.out.println("前置通知");
    }
    @After("pointdemo()")
    public void after(JoinPoint jp){
        System.out.println("后置通知-->"+ Arrays.toString(jp.getArgs()));
    }
    @AfterReturning(value = "pointdemo()",returning = "rv")
    public void returning(Object rv){
        System.out.println("返回通知-->"+rv);
    }
    @AfterThrowing(value = "pointdemo()",throwing = "e")
    public void throwing(Exception e){
        System.out.println("异常通知-->"+e.getMessage());
    }
    @Around("execution(* com.yl.entity.Calc.*(..))")
    public Object around(ProceedingJoinPoint pjp){
        System.out.println("环绕前置通知");
        Object obj = null;
        try {
            obj = pjp.proceed();
            System.out.println("环绕返回通知!");
        } catch (Throwable throwable) {
            System.out.println("异常通知!已将结果设置为0");
            obj = 0;
        }finally {
            System.out.println("环绕后置通知!");
        }
        return obj;
    }
}
测试
// 测试Aop
    @Test
    public void testCalc(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext01.xml");
        Calc c = context.getBean( "calc",Calc.class);
        Integer cheng = c.cheng(2, 5);
        System.out.println(cheng);
    }
配置
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       ">
    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.yl"/>
    <!-- 开启AOP的自动代理 -->
    <aop:aspectj-autoproxy/>
    <!--
        开启AOP的自动代理
            1、打开自动代理
            2、创建切面类,并交给SpringIOC容器管理,并注解@Aspect
            [3、]定义切点表示式,通过@Pointcut,注解在空方法上,根据方法名()进行调用
            4、定义通知方法
                @Before:前置通知
                @After:后置通知
                @AfterReturning:返回通知
                @AfterThrowing:异常通知
                @Around:环绕通知
    -->
</beans>

三、注解事务

开启事务的注解驱动
transaction-manager:指定当前事务驱动所使用的事务管理器
1、配置事务管理器
2、开事务的注解驱动
3、在需要使用事务的方法上打上@Transactional
propagation:传播行为
Propagation.REQUIRES_NEW:开启新事物
Propagation.REQUIRES:使用原来的事务
isolation:隔离级别
Isolation.READ_UNCOMMITTED:读未提交
Isolation.READ_COMMITTED:读已提交
Isolation.REPEATABLE_READ:可重复读
Isolation.SERIALIZABLE:序列化
timeout:事务的超时时间
read-only:事务是否只读
true:如果只读,则不会为该方法开启事务
false:会为该方法开启事务

案例
UserInfo.java
/**
 *用户信息实体类
 */
public class UserInfo {
    private Integer userId;
    private String userName;
    private String userPwd;
    private Integer userBalance;
    private Date userTime;
    public UserInfo(Integer userId, String userName, String userPwd, Integer userBalance, Date userTime) {
        this.userId = userId;
        this.userName = userName;
        this.userPwd = userPwd;
        this.userBalance = userBalance;
        this.userTime = userTime;
    }
    public UserInfo() {
    }
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserPwd() {
        return userPwd;
    }
    public void setUserPwd(String userPwd) {
        this.userPwd = userPwd;
    }
    public Integer getUserBalance() {
        return userBalance;
    }
    public void setUserBalance(Integer userBalance) {
        this.userBalance = userBalance;
    }
    public Date getUserTime() {
        return userTime;
    }
    public void setUserTime(Date userTime) {
        this.userTime = userTime;
    }
    @Override
    public String toString() {
        return "UserInfo{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userPwd='" + userPwd + '\'' +
                ", userBalance=" + userBalance +
                ", userTime=" + userTime +
                '}';
    }
}
UserInfoDao.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserInfoDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    /**
     * 修改用户余额方法
     * @param userName 用户名
     * @param money 钱
     * @return 返回受影响行数
     */
    public int updateUserBalanceByUserName(String userName,Integer money){
        return jdbcTemplate.update(" UPDATE user_info SET user_balance = user_balance + ? WHERE user_name = ? ",money,userName);
    }
    /**
     *  根据用户名查询用户余额
     * @param userName  用户名
     * @return  返回金额
     */
    public Integer selectUserInfoBalanceByUserName(String userName){
        return jdbcTemplate.queryForObject(" SELECT user_balance FROM user_info WHERE user_name = ? ",Integer.class,userName);
    }
}
UserInfoService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserInfoService {
    @Autowired
    private UserInfoDao userInfoDao;
    //事务需要具有一致性,要么都成功,要么都失败!
    /**
     * 转账功能
     * @param un1 转入的用户
     * @param un2 转出的用户
     * @param money 金额
     * @return 成功就返回 true
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.SERIALIZABLE,readOnly = false)
    public boolean zhuanZhang(String un1,String un2,Integer money){
        //un1加钱
        userInfoDao.updateUserBalanceByUserName(un1,money);
        //判断余额
        if(getUserBalanceByUserName(un2)<money){
            //当余额不足,则抛出余额不足异常
            throw new BalanceBuZu();
        }else{
            //un2减钱
            userInfoDao.updateUserBalanceByUserName(un2,-money);
        }
        return true;
    }
    /**
     * 根据用户账号查询余额
     * @param userName 用户名
     * @return 返回该用户的金额
     */
    public Integer getUserBalanceByUserName(String userName){
        return userInfoDao.selectUserInfoBalanceByUserName(userName);
    }
}
/**
 * 自定义异常
 */
class BalanceBuZu extends RuntimeException{
    public BalanceBuZu() {
        super("余额不足");
    }
}
配置
<?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:context="http://www.springframework.org/schema/context"
       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
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.yl"/>
    <!-- 开启AOP自动注解 -->
    <aop:aspectj-autoproxy/>
    <!--事务-->
    <bean name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource">
        </property>
    </bean>
    <!-- 配置数据源 -->
    <bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///user_db?characterEncoding=UTF-8"/>
        <property name="user" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
测试
public void test2(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext02.xml");
        UserInfoService uis = ac.getBean(UserInfoService.class);
        //至少两段数据库操作,一个账户减钱,一个账户加钱
        boolean bl = uis.zhuanZhang("admin1","admin2",1500);
        System.out.println(bl?"转账成功":"转账失败");
    }

四、全注解

MySpringConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration // 让该类变成Spring的配置类
/*
* includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
  )}
  * @ComponentScan(value = "com.zb.beisaomiao",useDefaultFilters = true,
        excludeFilters = @ComponentScan.Filter(
                type=FilterType.ANNOTATION,
                classes = {Controller.class, Repository.class})
)
* */

// 没有注解的方法(通过引入来注入)
@Import(value = {Test01.class, Test02.class})
public class MySpringConfiguration {

    /*
     *  1、注入Bean
     *      手动注入
     *          @Bean注解,注解在方法上,SpringIOC容器会自动调用该方法,将该方法返回的对象存入到SpringIOC容器中,默认beanName使用方法名
     *              value/name:指定其在SpringIOC容器中的name
     *              autowireCandidate:是否参与自动注入
     *              initMethod:初始化方法
     *              destroyMethod:销毁方法
     *      扫描注入
     *          @ComponentScan
     *      通过引入注入
     *          @Import
     *              value:要引入的类.class数组
     *      ... ...
     * */
    //<bean name="" class="" autowire="byType/byName" />
    @Bean(value ="userInfo", autowireCandidate = false,initMethod = "init",destroyMethod = "destory")
    public UserInfo getUserInfo(){
        UserInfo userInfo = new UserInfo();
        return userInfo;
    }
}
测试
import com.yl.cofiguration.MySpringConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestMain01 {
    public static void main(String[] args) {
        // 如果是通过Spring的配置类进行配置,则需要创建AnnotationConfigApplicationContext(配置类.class);
        ApplicationContext ac = new AnnotationConfigApplicationContext(MySpringConfiguration.class);
        String[] names = ac.getBeanDefinitionNames();
        for (String name : names){
            System.out.println(name);
        }
    }
}

五、作业

一、为工具类获取圆信息类通过SpringAOP完成代理增强

​ 描述:
​ 创建圆信息实现类,接口信息如下
​ public interface round{
​ public double getPerimeter(Double radius);//根据传入的半径参数,获取圆的周长
​ public double getArea(Double radius);//根据传入的参数半径,获取圆的面积
​ }
​ 要求使用Spring的AOP功能,为该实现类添加环绕通知
​ 通知要求:在进行计算之前验证参数是否合理(大于0)
​ 计算之后,结果保留两位有效数(四舍五入)字并返回

Round.java
public interface Round {
    //根据传入的半径参数,获取圆的周长
    public double getPerimeter(Double radius);
    //根据传入的参数半径,获取圆的面积
    public double getArea(Double radius);
}
RoundImpl.java
import org.springframework.stereotype.Component;
// 被通知的类
@Component
public class RoundImpl implements Round{
    /**
     * 计算周长
     * @param radius 圆的半径
     * @return  返回圆的周长
     */
    @Override
    public double getPerimeter(Double radius) {
        return Math.PI*radius*2;
    }
    /**
     * 计算面积
     * @param radius 圆的半径
     * @return 返回圆的面积
     */
    @Override
    public double getArea(Double radius) {
        return Math.PI*radius*radius;
    }
}
MyAspectRound.java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
// 通知类
@Component
@Aspect
public class MyAspectRound {
    // 切点
    @Pointcut(value = "execution(* com.yl.calculate.RoundImpl.*(..))")
    public void pointdemo(){}
    // 环绕通知
    @Around("pointdemo()")
    public Object around(ProceedingJoinPoint pjp){
        Object[] objnum = pjp.getArgs();
        Object obj = null;
        if((double)objnum[0]<0){
            throw new ling();
        }
        System.out.println("您输入的半径是:"+objnum[0]+"大于 0" );
        try {
            obj = pjp.proceed();
        } catch (Throwable throwable) {
            System.out.println("异常通知!已将结果设置为0");
            obj = 0;
        }finally {
            // 保留两位小数
            BigDecimal bg = new BigDecimal((double)obj);
            obj  = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        }
        return obj;
    }
}
// 自定义异常
class ling extends RuntimeException{
    public ling() {
        super("半径小于零");
    }
}
测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestRound {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        Round round = ac.getBean( Round.class);
        System.out.println("圆的周长为:"+round.getPerimeter(3.0));
        System.out.println("圆的面积为:"+round.getArea(4.0));
    }
}
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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.yl"/>
    <!-- 开启AOP自动注解 -->
    <aop:aspectj-autoproxy/>
</beans>
二、为服务层(BookInfoService)添加方法,并应用Spring声明式事务

​ public interface BookInfoService{
​ 购买图书方法
​ 判断图书数量是否大于等于购买数量
​ 等于:购买成功
​ 购买成功后,图书数量-1,用户积分+=图书单价*图书数量
​ 不等于:购买失败,抛出异常
​ public boolean buyBook(String userName,int quantity);
​ }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值