spring-wd

Spring自己的笔记

1.springIOC

  1. 在xml中注入bean。

    <?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 https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
     
        <!-- bean definitions here -->
     
        <bean id="hasParameterBean" class="com.cskaoyan.bean.HasParameterBean">
            <constructor-arg name="username" value="songge"/>
            <constructor-arg name="password" value="niupi"/>
        </bean>
     
        <!--静态工厂-->
        <!--factory-method属性:类中静态方法 -->
        <!--组件类型:不是class对应的类型 → factory-method方法的返回值类型-->
        <bean id="userFromStaticFactory" class="com.cskaoyan.factory.UserStaticFactory" factory-method="create"/>
        <!--实例工厂-->
        <bean id="instanceFactory" class="com.cskaoyan.factory.UserInstanceFactory"/>
        <!--factory-bean 引用容器中的工厂组件-->
        <!--factory-method factory-bean中的方法名-->
        <!--组件类型: → factory-method方法的返回值类型-->
        <bean id="userFromInstanceFactory" factory-bean="instanceFactory" factory-method="create"/>
     
        <!--FactoryBean组件类型是和getObject方法的返回值是相关的-->
        <bean id="userFromFactoryBean" class="com.cskaoyan.factory.UserFactoryBean"/>
     
    </beans>
    
  2. 使用注解的方式注入

        <!-- bean definitions here -->
        <!--base-package指的是com.cskaoyan这个包,及其子包-->
        <context:component-scan base-package="com.cskaoyan"/>
    

    注解的方式赋值:

        @Value("songgexxx")
    //    @Value("${userservice.username}")
        String username;
     
       <context:property-placeholder location="classpath:parameter.properties"/>
      
          
        //@Autowired
        //@Qualifier("userDaoImpl")
        //@Resource
        @Resource(name = "userDaoImpl2")//通过@Resource注解的name属性值指定组件id
                UserDao userDao; //从容器中取出userDao组件给到这个成员变量
    
    

2.AOP

aop的几种方式:

方式一:使用代理类ProxyFactoryBean,注意这种方式的目标类,必须有接口实现。

一个通知需要实现MethodInterceptor 接口。具体代码如下

    <!-- bean definitions here -->
    <context:component-scan base-package="com.cskaoyan"/>
    <bean id="helloServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="helloServiceImpl1"/>
        <!--interceptorNames接收的是字符串 👉 value属性-->
        <property name="interceptorNames" value="customAdvice"/>
    </bean>

通知:

@Component
public class CustomAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("正道的光");
        Object proceed = methodInvocation.proceed();//执行的是委托类的方法
        System.out.println("照在大地上");
        return proceed;
    }
}

测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class MyTest {
//@Autowired
//@Qualifier("helloServiceProxy")
//    @Resource(name = "helloServiceProxy")
//    HelloService helloService;
    @Autowired
    HelloService helloServiceProxy;
    @Test
    public void mytest1() {
        helloServiceProxy.sayHello();
    }
}

方式二:

加入依赖aspectjweaver依赖

通知是需要加入一个MethodInterceptor。主要的区别是xml文件中的区别。

有了pointcut了之后,就是通过advisor指定通知,pointcut这种方式可以指定特定的方法,进行指定加强,而不再是像之前那样对这个类的所有方法进行了增强。

<aop:config>
        <!--advice-ref:引用容器中的通知组件id-->
        <!--pointcut:切入点表达式 → 指定增强方法-->
        <!--<aop:advisor advice-ref="customAdvice" pointcut="execution(public void com.cskaoyan.service.HelloServiceImpl.sayHello())"/>-->
        <!--        <aop:pointcut id="helloPointcut" expression="execution(public void com.cskaoyan.service.HelloServiceImpl.sayHello())"/>-->
        <!--        <aop:advisor advice-ref="customAdvice" pointcut-ref="helloPointcut"/>-->
        <!--        <aop:advisor advice-ref="customAdvice" pointcut="execution(public void com.cskaoyan.service.HelloServiceImpl.sayHello())"/>-->
        <aop:advisor advice-ref="customAdvice" pointcut="execution(* com..*l.sayHello())"/>
    </aop:config>

pointcut的写作方式:

基本格式:execution(修饰符 返回值 包名.类名.方法名(形参))

修饰符是可以省略的,也就是直接不要了。

返回值,如果是javabean的话,写全类名。可以使用*来统配。

报名.类名.方法名(形参)

头尾不能省略,使用..代表中间任意部分。这里的头尾不能省略,那么也就是这个pointcut必须是指向一个特定的类中去了。好像是不可以指向一大片的类。

使用*通配。

"execution(* com..service.*Impl.*(..))"/><!--service层下的任意实现类组件下的任意包含单个参数的方法-->

方式三:方式二的升级版,有返回值,还有异常的返回。

而且是通知不需要实现MethodInterceptor接口了。

依赖:

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

通知变成了一个bean

package com.cskaoyan.asepct;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

/**
 * 要不通知对应的方法写在组件中
 */
@Component
public class CustomAspect {
    /**
     * 可以在通知方法的形参上增加一个参数JoinPoint
     */
    public void mybefore(JoinPoint joinPoint) {
        //Signature signature = joinPoint.getSignature();
        //String name = signature.getName();
        //System.out.println("马上执行" + name + "方法");
//
        //Object[] args = joinPoint.getArgs();
        //System.out.println(Arrays.asList(args));
//
        //Object target = joinPoint.getTarget();
        //Object aThis = joinPoint.getThis();
        //System.out.println("target = " + target);
        //System.out.println("this = " + aThis);
//
        //System.out.println("target class = " + target.getClass().getName());
        //System.out.println("this class = " + aThis.getClass().getName());

        System.out.println("正道的光");
    }

    public void myafter(/*JoinPoint joinPoint*/) {
        System.out.println("照在大地上");
    }

    public Object around(ProceedingJoinPoint joinPoint)/* throws Throwable*/ {
        System.out.println("around 的before");
        Object proceed = null;//类似于method.invoke 、methodInvocation.proceed
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            //throwable.printStackTrace();
            System.out.println("try catch住了");
        }
        System.out.println("around 的after");
        return proceed;
    }

    public void afterReturning(Object returnValue/*,JoinPoint joinPoint*/) {
        //String name = joinPoint.getSignature().getName();
        System.out.println("方法返回值为 " + returnValue);
    }

    public void afterThrowing(Exception exception) {
        System.out.println("抛出了 " + exception.getClass().getName() + "异常,异常信息是" + exception.getMessage());
    }
}

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 https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- bean definitions here -->
    <context:component-scan base-package="com.cskaoyan"/>

    <aop:config>
        <aop:pointcut id="customPointcut1" expression="execution(* com..service..*(..))"/>
        <aop:aspect ref="customAspect">
            <!--<aop:pointcut id="" expression=""/>-->
            <aop:before method="mybefore" pointcut="execution(* com..service..*(..))"/>
            <aop:before method="mybefore" pointcut-ref="customPointcut1"/>
            <aop:after method="myafter" pointcut-ref="customPointcut1"/>
            <aop:around method="around" pointcut-ref="customPointcut1"/>

            <aop:after-returning method="afterReturning" pointcut-ref="customPointcut1" returning="returnValue"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="customPointcut1" throwing="exception"/>
        </aop:aspect>
    </aop:config>
</beans>

方式四。就是方式三的注解方式。

依赖。通知如上

需要在xml中加入:

aop:aspectj-autoproxy/

package com.cskaoyan.asepct;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 要不通知对应的方法写在组件中
 */
@Aspect
@Component
public class CustomAspect {

    //需要方法辅助切入点的表达
    //修饰符可以为private或public
    //返回值为void
    //方法名 → pointcut的id
    //形参和方法体都为空
    //@Pointcut注解的value属性中写的是切入点表达式
    @Pointcut("execution(* com..service..*(..))")
    public void customPointcut(){}

    //@Before("execution(* com..service..*(..))")
    @Before("customPointcut()")
    public void mybefore(JoinPoint joinPoint){

        System.out.println("正道的光");
    }

    @After("customPointcut()")
    public void myafter(/*JoinPoint joinPoint*/){
        System.out.println("照在大地上");
    }

    @Around("customPointcut()")
    public Object around(ProceedingJoinPoint joinPoint)/* throws Throwable*/ {
        System.out.println("around 的before");
        Object proceed = null;//类似于method.invoke 、methodInvocation.proceed
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            //throwable.printStackTrace();
            System.out.println("try catch住了");
        }
        System.out.println("around 的after");
        return proceed;
    }

    @AfterReturning(value = "customPointcut()",returning = "returnValue")
    public void afterReturning(Object returnValue/*,JoinPoint joinPoint*/){
        //String name = joinPoint.getSignature().getName();
        System.out.println("方法返回值为 " + returnValue);
    }
    @AfterThrowing(value = "customPointcut()",throwing = "exception")
    public void afterThrowing(Exception exception){
        System.out.println("抛出了 " + exception.getClass().getName() + "异常,异常信息是" + exception.getMessage());
    }
}

将目标和通知彻底分开了。通知只是需要指向目标即可,我们在获取目标的时候,是自动增强这些方法的。

方式五,自定义注解的 方式,注解放在那里,就针对性的加强某个方法。

1.注解的自定义

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CountTime {}

2.通知的书写

package com.cskaoyan.asepct;

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;

@Aspect
@Component
public class CountTimeAspect {

    //@Pointcut注解的value属性中写 @annotation(自定义的注解) → 自定义注解出现在什么地方 → 什么地方就要被增强
    @Pointcut("@annotation(com.cskaoyan.anno.CountTime)")
    public void customPointcut(){}

    @Around("customPointcut()")
    public Object around(ProceedingJoinPoint joinPoint){
        long start = System.currentTimeMillis();
        Object proceed = null;
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println(joinPoint.getSignature().getName() + "方法的执行时间为" + (end - start));
        return proceed;
    }
}

目标类

package com.cskaoyan.service;

import com.cskaoyan.anno.CountTime;
import org.springframework.stereotype.Service;

@Service
public class HelloServiceImpl implements HelloService{
    @Override
    public void sayHello() {
        System.out.println("hello world");
    }

    @CountTime
    @Override
    public Integer add(Integer a, Integer b) {
        //long l = System.currentTimeMillis();
        int x = a + b;
        System.out.println("a + b的结果为" + x);
        //int i = 1/0;
        //long l1 = System.currentTimeMillis();
        //Thread.sleep(500);
        return x;
    }
}

3.Spring-TX

中间是学习了jdbcTemplate了。这个bean,主要是依赖了,DruidDataSource,使用的时候,直接取出来用就好了。

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/j24_db?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
 
    <bean class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

使用的时候,是直接取出来使用。

 
package com.cskaoyan.dao;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
 
@Repository
public class AccountDaoImpl implements AccountDao{
 
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Override
    public Integer selectMoneyById(Integer id) {
        Integer integer = jdbcTemplate.queryForObject("select money from j24_account_t where id = ?", Integer.class, id);
        return integer;
    }
 
    @Override
    public int update(Integer id, Integer money) {
        int update = jdbcTemplate.update("update j24_account_t set money = ? where id = ?", money, id);
        return update;
    }
}

方式一:Spring-Transaction-template

需要在容器中注入bean。TransactionTemplate,这个bean需要依赖DataSourceTransactionManager

<?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 https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- bean definitions here -->
    <context:component-scan base-package="com.cskaoyan"/>
    <!--application.xml-->
    <!--application-xxx.xml-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/j24_db?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
</beans>

service层:

package com.cskaoyan.service;

import com.cskaoyan.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

@Service
public class AccountServiceImpl implements AccountService{

    @Autowired
    TransactionTemplate transactionTemplate;

    @Autowired
    AccountDao accountDao;
    @Override
    public void transfer(Integer fromId, Integer destId, Integer money) {
        Integer fromMoney = accountDao.selectMoneyById(fromId) - money;
        Integer destMoney = accountDao.selectMoneyById(destId) + money;

        Integer execute = transactionTemplate.execute(new TransactionCallback<Integer>() {
            @Override
            public Integer doInTransaction(TransactionStatus transactionStatus) {
                accountDao.update(fromId, fromMoney);
                //int i = 1 / 0;
                accountDao.update(destId, destMoney);
                System.out.println(destMoney);
                return destMoney;
            }
        });//execute方法的返回值就是接收DoInTransaction方法的返回值
        System.out.println(execute);

    }
    @Override
    public void transfer2(Integer fromId, Integer destId, Integer money) {
        Integer fromMoney = accountDao.selectMoneyById(fromId) - money;
        Integer destMoney = accountDao.selectMoneyById(destId) + money;

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountDao.update(fromId, fromMoney);
                int i = 1 / 0;
                accountDao.update(destId, destMoney);
            }
        });
    }
}

方式二:transaction-proxy,指定了target。和transactionManager。

<?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 https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- bean definitions here -->
    <context:component-scan base-package="com.cskaoyan"/>
    <!--application.xml-->
    <!--application-xxx.xml-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/j24_db?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!--target-->
        <property name="target" ref="accountServiceImpl"/>

        <!--transactionManager-->
        <property name="transactionManager" ref="transactionManager"/>
        <!--transactionAttributes → Definition-->
        <property name="transactionAttributes">
            <props>
                <!--key方法名-->
                <!--
                    隔离级别:ISOLATION_XXX  → ISOLATION_REPEATABLE_READ、ISOLATION_DEFAULT
                    传播行为:PROPAGATION_XXX → PROPAGATION_REQUIRED、PROPAGATION_NESTED
                    超时:timeout_数字 单位是秒
                    只读:readOnly
                    -XXXException:rollBackFor
                    +xxxException:noRollBackFor
                -->
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
            </props>
        </property>
    </bean>
</beans>

目标代码:

package com.cskaoyan.dao;
public interface AccountDao {
    public Integer selectMoneyById(Integer id);
    public int update(Integer id, Integer money);
}


package com.cskaoyan.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import javax.sql.DataSource;

@Repository
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

    @Autowired
    public void setSuperDatasource(@Qualifier("dataSource") DataSource datasource){
        super.setDataSource(datasource);
    }
    //@Autowired
    //JdbcTemplate jdbcTemplate;
    @Override
    public Integer selectMoneyById(Integer id) {
        Integer integer = getJdbcTemplate().queryForObject("select money from j24_account_t where id = ?", Integer.class, id);
        return integer;
    }

    @Override
    public int update(Integer id, Integer money) {
        int update = getJdbcTemplate().update("update j24_account_t set money = ? where id = ?", money, id);
        return update;
    }
}



package com.cskaoyan.service;
public interface AccountService {
    void transfer(Integer fromId,Integer destId,Integer money);
}



package com.cskaoyan.service;

import com.cskaoyan.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountServiceImpl implements AccountService{

    @Autowired
    AccountDao accountDao;
    @Override
    public void transfer(Integer fromId, Integer destId, Integer money) {
        Integer fromMoney = accountDao.selectMoneyById(fromId) - money;
        Integer destMoney = accountDao.selectMoneyById(destId) + money;

        accountDao.update(fromId, fromMoney);
        int i = 1/0;
        accountDao.update(destId, destMoney);
    }
}

测试代码:

package com.cskaoyan;
import com.cskaoyan.dao.AccountDao;
import com.cskaoyan.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application.xml")
public class SpringTest {
    @Autowired
    @Qualifier("accountServiceProxy")
    AccountService accountService;
    @Test
    public void mytest3(){
        accountService.transfer(1,2,100);
    }
}

方式三:使用aop中的advisor

<?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- bean definitions here -->
    <context:component-scan base-package="com.cskaoyan"/>
    <!--application.xml-->
    <!--application-xxx.xml-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/j24_db?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com..service..*(..))"/>
    </aop:config>

    <!--tx提供了通知 👉 tx标签-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--name属性对应的是方法名-->
            <!--其他属性和definition相关-->
            <tx:method name="transfer*" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
</beans>

其他的不变。

方式四:注解的方式,最简单。

依赖:

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>

配置文件:

<?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/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- bean definitions here -->
    <context:component-scan base-package="com.cskaoyan"/>
    <!--application.xml-->
    <!--application-xxx.xml-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/j24_db?useUnicode=true&amp;characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--开启事务注解开关-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

使用过程:

package com.cskaoyan.service;

import com.cskaoyan.dao.AccountDao;
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
@Transactional//写在类上,意味着当前类(容器中的组件)的全部方法都增加事务
public class AccountServiceImpl implements AccountService{

    @Autowired
    AccountDao accountDao;
    //transactional注解中包含属性 👉 definition
    //@Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED,readOnly = true)
    //@Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED,timeout = 5)
    @Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED,noRollbackFor = ArithmeticException.class)
    @Override
    public void transfer(Integer fromId, Integer destId, Integer money) {
        Integer fromMoney = accountDao.selectMoneyById(fromId) - money;
        Integer destMoney = accountDao.selectMoneyById(destId) + money;

        accountDao.update(fromId, fromMoney);
        int i = 1 / 0;
        accountDao.update(destId, destMoney);
    }

}
  1. javaconfig的模式。

    package com.cskaoyan.config;
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.*;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import javax.sql.DataSource;
     
    @Configuration//组件注册可以写在配置类中,配置类本身也是容器中的组件
    @ComponentScan("com.cskaoyan")
    @PropertySource(value = "classpath:db.properties")
    @EnableAspectJAutoProxy
    @EnableTransactionManagement
    public class ApplicationConfiguration {
     
        /**
         * @Bean:注解的value属性可以指定id
         * 修饰符:public
         * 返回值:组件对应的class或其接口
         * 方法名:如果没有指定组件id,默认以方法名作为组件id
         * 形参:会从容器中取出该类型的组件,如果该类型组件不止一个,可以使用@Qualifier指定组件id
         * 方法体:获得一个组件对应的实例就可以了
         */
        //@Bean
        @Bean("datasource")
        //public DruidDataSource dataSource(){}
        public DataSource dataSource(){
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/j24_db?useUnicode=true&characterEncoding=utf-8");
            dataSource.setUsername("root");
            dataSource.setPassword("123456");
            return dataSource;
        }
        @Bean
        public JdbcTemplate jdbcTemplate(@Qualifier("datasource") DataSource dataSource){
            JdbcTemplate jdbcTemplate = new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
        @Bean
        public DataSourceTransactionManager transactionManager(DataSource dataSource){
            DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
            transactionManager.setDataSource(dataSource);
            return transactionManager;
        }
    }
    
posted @ 2022-03-19 23:06  孙立人bc  阅读(55)  评论(0)    收藏  举报