Spring入门

spring

@(JAVAWEB)

介绍(基于spring 4.2.4)
对象的容器,spring负责管理项目中的所有对象,可以看成是整个项目的管家
spring是一站式的框架
正因为是容器,容器中装了狠多对象比如web操作的对象,service的对象,dao的对象

spring搭建

  • 1.导包

这几个包,是spring的核心包(core)

image.png

导包之后并没有完成需要 创建xml文件
一般命名为applicationContext.xml

image.png

然后需要添加xml约束

添加xml约束.png

接下来是将类放入Spring的容器中

-新建User类

    @Component("user")
    //相当于xml文件中的an配置
    //最好用下面几种方式
    //@Service("user")
    //@Controller("user")
    //@Repository("user")
    //@Scope(scopeName = "prototy")//此属性来设置user类是否是单例还是多例默认单例。
    public class User {
    @Value("vv")//也可以添加到set方法上,在属性上面是通过反射的field进行赋值,而方法上是通过set方法赋值
    private String name;
    private int age;
    @Autowired //自动装配,前提是car类需要进行component等注解。
    //Autowired会有一问题当spring容器中有多个car类型的对象时,如car1,car2时可以使用下面两种注解
    //@Qualifier("car2") 不推荐此种需要和Autowired一起配合使用
    //@Resource(name = "car2")建议这种方式,当容器中有多个引用对象的时候
    private Car car;


    public User() {
        System.out.println("空参构造");
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }

    @PostConstruct //在对象创建之后调用等同于 init-method
    public void init() {
        System.out.println("我是初始化方法");
    }

    @PreDestroy //在销毁前调用
    public void destroy() {
        System.out.println("我是销毁方法");
    }
}

2.到applicationContext.xml中配置

xml添加约束

IDEA会自己生成Spring得约束XML文件


代码测试

代码测试.png

测试结果

测试结果.png

spring概念

IOC (Inverse Of Control) 概念:

将我们创建对象的方式反转,一千对象的创建由我们开发人员自己维护,包括依赖关系也是自己注入.

使用了Spring之后,对象的创建和依赖关系可以由Spring完成创建以及注入.
简单来说就是:反转了对象的创建方式,有自己创建变为了程序控制.

DI(dependency Injection):实现IOC思想需要DI支持

注入方式:

  • 1.set方式
  • 2.构造方法注入
  • 3.字段注入

注入类型:

  • 值类型注入:基本数据类型
  • 引用类型注入:将依赖对象注入

applicationContext和anfactory

BeanFactory
Spring原始接口的实现类功能单一
anFactory接口实现类的容器,特点是每次在获得对象时才会创建对象。
applicationContext
特点:每次容器启动时就会创建容器中配置的所有对象。
提供了更多功能。
从类路劲下加载配置文件:classPathXMLApplicationContext
从硬盘绝对路劲下加载配置文件FilePathXMLApplicationContext
web开发中使用applicationContext,在资源匮乏的环境可以使用anFactory。

spring配置详解

Bean元素

Bean元素.png

Spring创建对象方式
1.空参构造方式
静态工厂方式
动态工厂方式
an元素晋级
scope属性
singleton(默认)单例对像,spring容器中只会存在一个实例
prototype(多例):每次获得时都会创建对象。和struts2使用时必须配置为多例。
request:web环境下对象鱼request对象生命周期一样
session:web环境下雨session声明周期一致
生命周期属性:配置一个方法作为声明周期初始化方法。spring会在对象创建之后首先调用
配置一个而方法作为生命周期的销毁方法,spring会在结束前调用该方法。
spring的分模块化配置

Spring属性注入:set方法
在user中添加car属性

在user中添加car属性.png

加上car对象

加上car对象.png

两个都要重写toStirng方法

目录结构
xml中配置

xml中配置.png

测试代码

测试代码.png

测试结果

测试结果.png

构造函数注入

构造函数注入.png
构造函数注入.png

或者

image.png

p名称空间注入

p名称空间注入.png

spel注入

spel注入.png

复杂类型注入(了解)

用注解配置xml
在原来的lib上添加

在原来的lib上添加.png

步骤
1.为主配置文件引入新的命名空间(约束)
通添加xml约束一样。
2.开启注解配置文件

image.png.png

3.在类中使用注解。
1)类注解

类注解.png

2)值注入

值注入.png

3)引用类型注入

引用类型注入.png

4)初始化、销毁注入

初始化、销毁注入.png

spring与junit整合
首先导包

导包.png
测试.png

spring中的AOP

思想:横向重复,纵向抽取。
对目标对象中的方法进行增强.
具体还清楚

spring中的aop原理

动态代理(优先)

被代理的对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理及技术

cglib

第三方代理技术,cglib代理可以对任何类生成代理,代理的原理是对目标对象进行继承代理,如果目标对象呗final修饰,那么该类无法被cglib代理。

aop名词
joinpoint(连接点):目表对象中,所有增强的方法。
pointcut(切入点):目标对象中,已经增强的方法。
advice(通知/增强):增强的代码。
Target(目标对象):被代理对象,代码中的UserSevviceImpl
Weaving(织入):将通知应用到切入的点的过程
Proxy:将通知织入大目标对象后,形成代理对象。
aspect(切面):切入点+通知。

Spring中的aop演示

1.导包4+2+2+2:

导包.png

2.准备目标对象

/**
 * Created by Bove_shu on 2017/6/9.
 */
public class UserServiceImp implements UserService {
    @Override
    public void save() {

        System.out.println("保存用户");

    }

    @Override
    public void delete() {
        System.out.println("删除用户");
    }

    @Override
    public void update() {
        System.out.println("更新用户");
    }

    @Override
    public void find() {
        System.out.println("查找用户");
    }
}

3.准备通知

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 通知类
 * Created by Bove_shu on 2017/6/9.
 */
public class MyAdvice {

    //前置通知
    //  |-目标方法运行之前调用
    //后置通知(如果出现异常不会调用)
    //  |-在目标方法运行之后调用
    //环绕通知
    //  |-在目标方法之前之后都调用
    //异常拦截通知
    //  |-如果出现异常,就会调用
    //后置通知
    //  |-目标方法调用之后


    //前置通知
    public void fore() {
        System.out.println("这是前置通知");
    }

    //后置通知
    public void afterReturning() {
        System.out.println("这是后置通知(如果出现异常不会调用)");
    }

    //环绕通知
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("这是环绕前置通知");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("这是环绕后置通知(如果出现异常不会调用)");
        return proceed;
    }

    //异常通知
    public void afterException() {
        System.out.println("出事啦!");
    }

    //后置通知
    public void after() {
        System.out.println("这是后置通知出现异常也会调用");
    }

}

4.配置进行织入,将通知织入目标对象。

Spring中的Aop配置(xml配置)

<?xml version="1.0" encoding="UTF-8"?>
<ans xmlns="http://www.springframework.org/schema/ans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/ans
       http://www.springframework.org/schema/ans/spring-ans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    <!--aop配置主要是上面两行-->
    <!--指定扫描an包下的所有类中的注解,an下所有包都要扫描-->
    <!--//目标配置对象-->

    <an name="userServiceTarget" class="Service.UserServiceImp"></an>
    <!--配置通知对象-->
    <an name="myAdvice" class="Aspect.MyAdvice"></an>
    <!--配置将通知织入目标对象-->
    <aop:config>
        <!--配置切入点-->
        <!--
         void Service.UserServiceImp.save() 表示对修饰符不受限制
         * Service.UserServiceImp.save()  标识对修饰符和返回值不做限制
         * Service.UserServiceImp.*() 表示对UserServiceImp类下所有的空参方法进行增强.
         * Service.UserServiceImp.*(..) 表示对UserServiceImp类下所有的方法进行增强.
         * Service.*ServiceImp.*(..) 表示从service包下找以ServiceImp的所有类.
          * Service..*ServiceImp.*(..)表示从service包下找以ServiceImp的所有类(包括子包)
        -->
        <aop:pointcut id="pc" expression="execution(* Service..*ServiceImp.*(..))"/>
        <aop:aspect ref="myAdvice">
            <aop:fore method="fore" pointcut-ref="pc"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pc"/>
            <aop:around method="around" pointcut-ref="pc"/>
            <!--异常-->
            <aop:after-throwing method="afterException" pointcut-ref="pc"/>
            <aop:after method="after" pointcut-ref="pc"/>
        </aop:aspect>
    </aop:config>
</ans>

Spring中的Aop配置(注解配置)

前两步步和上面一样

  1. 准备通知对象
 /**
 * 通知类
 * Created by Bove_shu on 2017/6/9.
 */
@Aspect
//标识该类是通知类
public class MyAdvice {

    //前置通知
    //  |-目标方法运行之前调用
    //后置通知(如果出现异常不会调用)
    //  |-在目标方法运行之后调用
    //环绕通知
    //  |-在目标方法之前之后都调用
    //异常拦截通知
    //  |-如果出现异常,就会调用
    //后置通知
    //  |-目标方法调用之后
@Pointcut("execution(* Service..*ServiceImp.*(..))")
public void pc(){

}
    //前置通知
    @fore("MyAdvice.pc())")
    public void fore() {
        System.out.println("这是前置通知");
    }

    //后置通知
    @AfterReturning("MyAdvice.pc())")
    public void afterReturning() {
        System.out.println("这是后置通知(如果出现异常不会调用)");
    }

    //环绕通知
    @Around("MyAdvice.pc())")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("这是环绕前置通知");
        Object proceed = pjp.proceed();//调用目标方法
        System.out.println("这是环绕后置通知(如果出现异常不会调用)");
        return proceed;
    }

    //异常通知
    @AfterThrowing("MyAdvice.pc())")
    public void afterException() {
        System.out.println("出事啦!");
    }

    //后置通知
    @After("MyAdvice.pc())")
    public void after() {
        System.out.println("这是后置通知出现异常也会调用");
    }

}
  1. 将通知织入目标对象
<?xml version="1.0" encoding="UTF-8"?>
<ans xmlns="http://www.springframework.org/schema/ans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/ans
       http://www.springframework.org/schema/ans/spring-ans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
    <!--aop配置主要是上面两行-->
    <!--指定扫描an包下的所有类中的注解,an下所有包都要扫描-->
    <!--//目标配置对象-->

    <an name="userServiceTarget" class="Service.UserServiceImp"></an>
    <!--配置通知对象-->
    <an name="myAdvice" class="AnnotationAspect.MyAdvice"></an>
    <!--开启注解完成织入-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</ans>

Spring整合JDBC

spring中提供了一个可以操作数据库的对象,对象封装了JDBC技术.
JDBCTemplate JDBC模板

  1. 准备工作(4+2)
  2. Spring-test包+spring-aop包 jdbc驱动 连接池c3p0 spring-jdbc spring-tx(事务)
  3. jdbc驱动 连接池c3p0
准备工作.png

代码(没用用spring配置的代码):

  1. 需要一个springJDBC模板(该类是接口)定义该类的方法
/**
 * Created by Bove_shu on 2017/6/11.
 */
public interface UserDao {
    //增
    void save(TUser user);

    // 删

    void update(TUser user);
    // 改
    void delete(int id);


    TUser getById(int id);

    // 查
    int getTotalCount();

    //查
    List<TUser> getAll();
}

2.模板的实现类.具体些数据库操作.

/**
 * Created by Bove_shu on 2017/6/11.
 */
public class UserDaoImpl implements UserDao {
    private JdbcTemplate jt;

    public JdbcTemplate getJt() {
        return jt;
    }

    public void setJt(JdbcTemplate jt) {
        this.jt = jt;
    }

    @Override
    public void save(TUser user) {
        String sql = "insert into t_user values(null,?)";
        jt.update(sql, user.getName());
    }

    @Override
    public void update(TUser user) {
        String sql = "UPDATE  t_user SET NAME =? WHERE id=?";
        jt.update(sql, user.getName(), user.getId());
    }

    @Override
    public void delete(int id) {
        String sql = "delete from t_user where id=?";
        jt.update(sql, id);
    }

    @Override
    public TUser getById(int id) {
        String sql = "SELECT  * from t_user where id=?";
        //这里使用new RowMapper来进行查找  第一个参数resultSet是查询结果的集合,从set中抽取结果放入TUser类中
        //                                        第二个参数是方法调用了几次,就是几.
        jt.queryForObject(sql, (resultSet, i) -> {
            TUser u = new TUser();
            u.setId(resultSet.getInt("id"));
            u.setName(resultSet.getString("name"));
            return u;
        }, id);
        return null;

    }

    @Override
    public int getTotalCount() {
        String sql = "SELECT  count(*) from t_user where id=?";
//        返回个数就用下面的这行代码
        Integer count = jt.queryForObject(sql, Integer.class);
        return count;
    }

    @Override
    public List<TUser> getAll() {
        String sql = "SELECT  * from t_user ";
        //放回集合是下面的代码,这不需要list.add的方法,你只需要做对Tuser的赋值即可.
        List<TUser> list = jt.query(sql, new RowMapper<TUser>() {
            @Override
            public TUser mapRow(ResultSet resultSet, int i) throws SQLException {
                TUser u = new TUser();
                u.setId(resultSet.getInt("id"));
                u.setName(resultSet.getString("name"));
                return u;
            }
        });
        return list;
    }
}
  1. 测试代码
 @Test
    public void test() throws PropertyVetoException {
        //准备连接池
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.jdbc,Driver");
        dataSource.setJdbcUrl("jdbc:mysql:///spring-jdbc");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        //1 创建JDBC模板对象
        JdbcTemplate jt = new JdbcTemplate();
        jt.setDataSource(dataSource);
        //2书写sql执行
        String sql="insert into t_user values(null,'vv')";
        jt.update(sql);
    }

使用spring配置写代码

  1. 首先要将用到的类放到容器中,从最底层的开始放入容器中(那个类是最底层可以参考上面的测试代码)
<?xml version="1.0" encoding="UTF-8"?>
<ans xmlns="http://www.springframework.org/schema/ans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/ans
       http://www.springframework.org/schema/ans/spring-ans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定扫描an包下的所有类中的注解,an下所有包都要扫描-->
    <!--<context:component-scan base-package="an"></context:component-scan>-->

    <!--将连接池放入spring容器-->
    <an name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"/>
        <property name="driverClass" value="com.mysql.jdbc,Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring-jdbc"/>
    </an>
    <!--将JDbcTemplate放入容器-->
    <an name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </an>
    <!--将userDao放入容器-->
        <an name="userDao" class="SpringJDBC.UserDaoImpl">
            <property name="jt" ref="jdbcTemplate"/>
        </an>

</ans>
  1. dao的实现类不变(模板的实现类不变)

  2. 使用sping测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class jdbcTest {
    @Autowired
    UserDao userDao;
    @Test
    public void test() throws PropertyVetoException {
        //准备连接池
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("com.mysql.jdbc,Driver");
        dataSource.setJdbcUrl("jdbc:mysql:///spring-jdbc");
        dataSource.setUser("root");
        dataSource.setPassword("root");
        //1 创建JDBC模板对象
        JdbcTemplate jt = new JdbcTemplate();
        jt.setDataSource(dataSource);
        //2书写sql执行
        String sql="insert into t_user values(null,'vv')";
        jt.update(sql);
    }
    @Test
    public void save() throws PropertyVetoException {
        TUser u=new TUser();
        u.setName("bove");
        userDao.save(u);
    }
    @Test
    public void update() throws PropertyVetoException {
        TUser u=new TUser();
        u.setName("bove");
        u.setId(2);
        userDao.update(u);
    }
}

另一种方式
继承JDBCDaoSupport
我只写了一种方式其他方法我就不完善了. 之前的jt用getJdbcTemplate()代替 ,
并且容器中也不需要再配置.
xml配置

<ans xmlns="http://www.springframework.org/schema/ans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/ans
       http://www.springframework.org/schema/ans/spring-ans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定扫描an包下的所有类中的注解,an下所有包都要扫描-->
    <!--<context:component-scan base-package="an"></context:component-scan>-->

    <!--将连接池放入spring容器-->
    <an name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"/>
        <property name="driverClass" value="com.mysql.jdbc,Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring-jdbc"/>
    </an>
    <!--将JDbcTemplate放入容器-->
    <!--<an name="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">-->
        <!--<property name="dataSource" ref="dataSource"></property>-->
    <!--</an>-->
    <!--将userDao放入容器-->
        <an name="userDao" class="SpringJDBC.UserDao2">
            <!--<property name="jt" ref="jdbcTemplate"/>-->
            <property name="dataSource" ref="dataSource"/>
        </an>

</ans>

代码

public class UserDao2 extends JdbcDaoSupport implements UserDao {
    
    @Override
    public void save(TUser user) {
        String sql = "insert into t_user values(null,?)";
        //这里
        getJdbcTemplate().update(sql, user.getName());
    }

    @Override
    public void update(TUser user) {

    }

    @Override
    public void delete(int id) {

    }

    @Override
    public TUser getById(int id) {
        return null;
    }

    @Override
    public int getTotalCount() {
        return 0;
    }

    @Override
    public List<TUser> getAll() {
        return null;
    }


}

Spring中的事务

事务:要么成功要么失败.
事务特性:acid(原子性,一致性,持久性,隔离性)

事务的并发问题:脏读,幻读,不可重复读.
事务的隔离级别:
1读未提交
2读已提交
4可重复度
8串行化

spring封装了事务管理代码

事务操作

打开事务
提交事务
回滚事务
事务操作

事务操作对象
因为在不同平台,操作事务的代码各不相同,springs提供了一个接口.
PlatformTransactionManager接口,这个接口是spring中最重要的对象
JDBCTransactionManager
HirbateTransactionManager

spring管理事务的属性介绍
事务的隔离级别
是否只读
事务的传播行为
事务传播行为

事务传播行为.png

spring管理事务的方式
编码式(不推荐)
1.蒋核心事务管理器配置到容器中

<ans xmlns="http://www.springframework.org/schema/ans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/ans
       http://www.springframework.org/schema/ans/spring-ans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定扫描an包下的所有类中的注解,an下所有包都要扫描-->
    <!--<context:component-scan base-package="an"></context:component-scan>-->

    <!--事务核心管理器,封装了所有事务操作,依赖于连接池.-->
    <an name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </an>
    <!--事务模板-->
    <an name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </an>


    <!--将连接池放入spring容器-->
    <an name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"/>
        <property name="driverClass" value="com.mysql.jdbc,Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring-jdbc"/>
    </an>
    
    <an name="accountDao" class="tx.Dao.AccountDaoimpl">
        <property name="dataSource" ref="dataSource"/>
    </an>
    <an name="accountService" class="tx.Service.AccountServiceImpl">
        <property name="dao" ref="accountDao"/>
        <property name="tt" ref="transactionTemplate"/>
    </an>
</ans>

2.代码中使用

public class AccountServiceImpl implements AccountService {

    private AccountDao dao;
    private TransactionTemplate tt;

    public void setTt(TransactionTemplate tt) {
        this.tt = tt;
    }

    public AccountDao getDao() {
        return dao;
    }

    public void setDao(AccountDao dao) {
        this.dao = dao;
    }

    @Override
    public void transfer(int from, int to, double money) {
        tt.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                //捡钱
                dao.decreaseMoney(from, money);
                //加钱
                dao.increaseMoney(to, money);
            }
        });

    }
}

aopxml配置
准备工作导包
导入新的约束
配置通知
xml配置

<?xml version="1.0" encoding="UTF-8"?>
<ans xmlns="http://www.springframework.org/schema/ans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/ans
       http://www.springframework.org/schema/ans/spring-ans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
      http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定扫描an包下的所有类中的注解,an下所有包都要扫描-->
    <!--<context:component-scan base-package="an"></context:component-scan>-->

    <!--事务核心管理器,封装了所有事务操作,依赖于连接池.-->
    <an name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </an>
    <!--事务模板-->
    <an name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </an>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--name->代表方法名-->
            <!--isolation->代表隔离级别-->
            <!--propagation->传播行为-->
            <!--read-only->是否只读-->
            <tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
        </tx:attributes>
    </tx:advice>

    <!--将通知织入目标对象-->
    <aop:config>
        <aop:pointcut id="txPc" expression="execution(* tx.Service.*AccountServiceImpl.*(..))"></aop:pointcut>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"/>

    </aop:config>
    <!--将连接池放入spring容器-->
    <an name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"/>
        <property name="driverClass" value="com.mysql.jdbc,Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring-jdbc"/>
    </an>

    <an name="accountDao" class="tx.Dao.AccountDaoimpl">
        <property name="dataSource" ref="dataSource"/>
    </an>
    <an name="accountService" class="tx.Service.AccountServiceImpl">
        <property name="dao" ref="accountDao"/>
        <property name="tt" ref="transactionTemplate"/>
    </an>
</ans>

当需要开启事务的方法有很多的时候,可以用下面的方法进行

image.png

*表示通配符

注解配置
准备工作导包
导入新的约束
开启注解管理事务
首先需要到xml中配置

<?xml version="1.0" encoding="UTF-8"?>
<ans xmlns="http://www.springframework.org/schema/ans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/ans
       http://www.springframework.org/schema/ans/spring-ans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
      http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--指定扫描an包下的所有类中的注解,an下所有包都要扫描-->
    <!--<context:component-scan base-package="an"></context:component-scan>-->

    <!--事务核心管理器,封装了所有事务操作,依赖于连接池.-->
    <an name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
    </an>
    <!--事务模板-->
    <an name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    <property name="transactionManager" ref="transactionManager"/>
    </an>

   
    主要是这行
    <tx:annotation-driven/>
    <!--将连接池放入spring容器-->
    <an name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"></property>
        <property name="password" value="root"/>
        <property name="driverClass" value="com.mysql.jdbc,Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///spring-jdbc"/>
    </an>

    <an name="accountDao" class="tx.Dao.AccountDaoimpl">
        <property name="dataSource" ref="dataSource"/>
    </an>
    <an name="accountService" class="tx.Service.AccountServiceImpl">
        <property name="dao" ref="accountDao"/>
        <property name="tt" ref="transactionTemplate"/>
    </an>
</ans>

代码层

//代表类中的所有方法都采用此事务,当个别不一样的时候在方法上面加此注解就行了
@Transactional(isolation = Isolation.REPEATABLE_READ ,propagation = Propagation.REQUIRED,readOnly = false)
public class AccountServiceImpl implements AccountService {

    private AccountDao dao;
    private TransactionTemplate tt;

    public void setTt(TransactionTemplate tt) {
        this.tt = tt;
    }

    public AccountDao getDao() {
        return dao;
    }

    public void setDao(AccountDao dao) {
        this.dao = dao;
    }

//    @Override
//    public void transfer(int from, int to, double money) {
//        tt.execute(new TransactionCallbackWithoutResult() {
//            @Override
//            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
//                //捡钱
//                dao.decreaseMoney(from, money);
//                //加钱
//                dao.increaseMoney(to, money);
//            }
//        });
//
//    }
    @Override
    //个别不一样的时候在方法上面加此注解就行了
    @Transactional(isolation = Isolation.REPEATABLE_READ ,propagation = Propagation.REQUIRED,readOnly = true)
    public void transfer(int from, int to, double money) {

                //捡钱
                dao.decreaseMoney(from, money);
                int a=1/0;
                //加钱
                dao.increaseMoney(to, money);
    }
}

当前的事务管理用到的类

目录结构

目录结构.png

AccountDao类

public interface AccountDao {
    //价钱
    void increaseMoney(int id,Double money);
    //捡钱
    void decreaseMoney(int id,Double money);
}

AccountDaoimpl类

public class AccountDaoimpl extends JdbcDaoSupport implements AccountDao {
    @Override
    public void increaseMoney(int id, Double money) {
        getJdbcTemplate().update("UPDATE t_account SET  money=money+? WHERE id=?",money,id);
    }

    @Override
    public void decreaseMoney(int id, Double money) {
        getJdbcTemplate().update("UPDATE t_account SET  money=money-? WHERE id=?",money,id);
    }
}

AccountService类

public interface AccountService {
    //转账方法
    void transfer(int from,int to,double money);
}

AccountServiceImpl类

//代表类中的所有方法都采用此事务,当个别不一样的时候在方法上面加此注解就行了
@Transactional(isolation = Isolation.REPEATABLE_READ ,propagation = Propagation.REQUIRED,readOnly = false)
public class AccountServiceImpl implements AccountService {

    private AccountDao dao;
    private TransactionTemplate tt;

    public void setTt(TransactionTemplate tt) {
        this.tt = tt;
    }

    public AccountDao getDao() {
        return dao;
    }

    public void setDao(AccountDao dao) {
        this.dao = dao;
    }

//    @Override
//    public void transfer(int from, int to, double money) {
//        tt.execute(new TransactionCallbackWithoutResult() {
//            @Override
//            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
//                //捡钱
//                dao.decreaseMoney(from, money);
//                //加钱
//                dao.increaseMoney(to, money);
//            }
//        });
//
//    }
    @Override
    //个别不一样的时候在方法上面加此注解就行了
    @Transactional(isolation = Isolation.REPEATABLE_READ ,propagation = Propagation.REQUIRED,readOnly = true)
    public void transfer(int from, int to, double money) {

                //捡钱
                dao.decreaseMoney(from, money);
                int a=1/0;
                //加钱
                dao.increaseMoney(to, money);
    }
}

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test {
    @Autowired
    private AccountService as;
    @org.junit.Test
    public void test(){
        as.transfer(1,2,200);
    }
}

end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,932评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,554评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,894评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,442评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,347评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,899评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,325评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,980评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,196评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,163评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,085评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,826评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,389评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,501评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,753评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,171评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,616评论 2 339

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,547评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,705评论 6 342
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,426评论 1 133
  • 我看着书桌上平睡的钢笔,或许正在做一个关于文字的梦。这种梦境或许真实或许虚假,但终归是一支钢笔的梦。在梦里面它或许...
    刀爷阅读 451评论 4 3