Spring 使用注解方式进行事务管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 使用注解方式进行事务管理相关的知识,希望对你有一定的参考价值。

参考技术A

使用步骤:

事务的传播行为和隔离级别

大家在使用spring的注解式事务管理时,对事务的传播行为和隔离级别可能有点不知所措,下边就详细的介绍下以备方便查阅。

事物注解方式: @Transactional

当标于类前时, 标示类中所有方法都进行事物处理 , 例子:

当类中某些方法不需要事物时:

事物超时设置:
@Transactional(timeout=30) //默认是30秒

事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化

mysql: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED

脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说,
后续读取可以读到另一事务已提交的更新数据. 相反, "可重复读"在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据

@Transactional注解中常用参数说明

续表)

注意的几点:
1 @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.

2用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException("注释");)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception("注释");)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚 要想所有异常都回滚,要加上 @Transactional( rollbackFor=Exception.class,其它异常) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
如下:
@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
public void methodName()
throw new Exception("注释");


@Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚
public ItimDaoImpl getItemDaoImpl()
throw new RuntimeException("注释");

3、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。


4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 元素的出现 开启 了事务行为。


5、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因 此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。

Spring管理Bean(XML与注解方式)

文章目录

什么是Bean管理?

bean管理其实指的是这两个操作:

  1. 创建对象
  2. 注入属性

Spring是如何管理Bean的?

Spring通过IoC容器来管理Bean,我们可以通过XML配置或者注解配置,来指导IoC容器对Bean的管理。因为注解配置比XML配置方便很多,所以现在大多时候会使用注解配置的方式。

下面分别来看一下:

环境准备

新建maven项目,引入依赖

<!--  引入依赖  -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

基于xml方式注入属性

第一种注入方式:使用set方式进行注入。

实现步骤如下所示:

创建类,定义属性和对应的set方法;

public class Book 
    //创建属性
    private String bname;
    private String bauthor;

    //创建属性对应的set方法
    public void setBname(String bname)
        this.bname = bname;
    
    public void setBauthor(String bauthor) 
        this.bauthor = bauthor;
    

在spring配置文件配置对象创建(<bean>标签),配置属性注入(<bean>标签内部的<property>标签)。注入属性在创建对象的基础之上完成,先创建对象,在注入属性。

<!-- set方法注入属性-->
<bean id = "book" class="com.yyl.entity.Book">
    <!-- 使用property完成属性注入
            name: 类里面属性名称
            value:向属性注入的值
        -->
    <property name="bname" value="从你的全世界路过"></property>
    <property name="bauthor" value="张嘉佳"></property>
</bean>

对xml方式使用set进行注入的测试:

@Test
public void SetterBean() 
    // 1. 加载spring 配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 2. 获取配置创建的对象
    Book book = context.getBean("book", Book.class);
    System.out.println(book.hashCode());
    System.out.println(book.toString());

测试结果:

第二种注入方式:使用有参数的构造函数进行注入

实现步骤如下所示:

创建类,定义属性,创建属性对应的有参数构造方法

public class Orders 
    //属性
    private String name;
    private String address;
    //多参数构造函数
    public Orders(String name, String address) 
        this.name = name;
        this.address = address;
    

在spring配置文件中进行配置:

<!-- 使用有参构造函数注入属性-->
<bean id="orders" class="com.yyl.entity.Orders">
    <constructor-arg name="name" value="衣架"></constructor-arg>
    <constructor-arg name ="address" value="china"></constructor-arg>
</bean>

对xml方式使用有参构造注入的测试:

@Test
public void ConstructorBean() 
    // 1. 加载spring 配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 2. 获取配置创建的对象
    Orders orders = context.getBean("orders", Orders.class);
    System.out.println(orders.hashCode());
    System.out.println(orders.toString());

测试结果:

注解配置

以下是管理Bean时常用的一些注解:

  1. @ComponentScan用于声明扫描策略,通过它的声明,容器就知道要扫描哪些包下带有声明的类,也可以知道哪些特定的类是被排除在外的。

  2. @Component、@Repository、@Service、@Controller用于声明Bean,它们的作用一样,但是语义不同。@Component用于声明通用的Bean,@Repository用于声明DAO层的Bean,@Service用于声明业务层的Bean,@Controller用于声明视图层的控制器Bean,被这些注解声明的类就可以被容器扫描并创建。

  3. @Autowired、@Qualifier用于注入Bean,即告诉容器应该为当前属性注入哪个Bean。其中,@Autowired是按照Bean的类型进行匹配的,如果这个属性的类型具有多个Bean,就可以通过@Qualifier指定Bean的名称,以消除歧义。

  4. @Scope用于声明Bean的作用域,默认情况下Bean是单例的,即在整个容器中这个类型只有一个实例。可以通过@Scope注解指定prototype值将其声明为多例的,也可以将Bean声明为session级作用域、request级作用域等等,但最常用的还是默认的单例模式。

  5. @PostConstruct、@PreDestroy用于声明Bean的生命周期。其中,被@PostConstruct修饰的方法将在Bean实例化后被调用,@PreDestroy修饰的方法将在容器销毁前被调用。

半注解式代码

配置文件中 配置的扫描不再用<bean>标签,而是扫描包下注解:

<!--    扫描注入-->
<context:component-scan base-package=""></context:component-scan>

下面我们进行测试:
修改xml文件:

<!--配置扫面-->
<!--配置扫描带有四大注解类:@Controller、@Service、@Repository、@Component,交给spring统一管理-->
<context:component-scan base-package="com.yyl"></context:component-scan>

编写User类

package com.yyl.entity;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component(value = "user")
public class User 

    @Value("18")
    private int age;

    @Value("玉如梦")
    private String name;

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

编写测试代码:

@Test
public void AnnotationBean()
    // 1. 加载spring 配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 2. 获取配置创建的对象
    User user = context.getBean("user", User.class);
    System.out.println(user);

运行结果:

纯注解代码

编写配置类:

package com.yyl.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration//声明配置类
@ComponentScan(value = "com.yyl")  //扫描具体的包
public class SpringConfig 


编写测试代码:

@Test
public void AnnotationBean2()
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    User user = context.getBean("user",User.class);
    System.out.println(user);

运行结果:

以上是关于Spring 使用注解方式进行事务管理的主要内容,如果未能解决你的问题,请参考以下文章

Spring 使用注解方式进行事务管理

Spring 使用注解方式进行事务管理

Spring 使用注解方式进行事务管理

Spring管理Bean(XML与注解方式)

Spring基础(十六):Spring事务管理注解方式和XML配置方式

Spring 事务注解@Transactional