目录
Spring框架
一、Spring初体验
1.1 Spring简介
认识Spring:
Spring提供一站式解决方法,对开发的各层都有提供支持。
Spring 体系结构:
Spring 由 20 多个模块组成,它们可以分为数据访问/集成(Data Access/Integration)、 Web、面向切面编程(AOP, Aspects)、提供JVM的代理 (Instrumentation)、消息发送(Messaging)、 核心容器(Core Container)和测试(Test)。
Spring特性:
- 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API。
class HelloServlet extends HttpServlet{ // 处理请求的类:侵入式设计; servlet侵入
}
class HelloHandler { // 处理请求的类: 非侵入式设计
}
- 容器:Spring是一个容器,因为它包含并且管理应用对象的生命周期。
- 组件化:Spring实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。
- 一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的JDBCTemplate)。
IOC 容器:
Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。
Inversion of control 控制反转容器
之前:我们用对象,自己new
现在:我们用对象,去ioc容器中获取,对象怎么创建的不用管,只要去用就行了。
IOC 作用: 帮助我们创建对象、管理对象的生命周期。
User user = new user() 创建对象
DI dependency injection 依赖注入
class UserService {
private UserDao userDao
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
public void save(){
userdao.saveUser();
}
}
UserSevice us = new UserService(); // IOC: 创建对象
us.setUserDao(userDao); // IOC: 管理对象的依赖关系,DI,依赖注入
us.save(); // 报错
1.2 入门案例
- 导入jar包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
</dependencies>
-
编写核心配置文件
-
配置文件路径:src/main/resources
-
示例代码
-
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置需要创建的对象-->
<!--
bean 用来配置需要创建的对象
id 对象的名称,从容器中获取对象可以通过id
class 对象的全路径
scope 对象的范围
singlton 默认;单例的对象;创建容器的时候自动创建
prototype 多例; 每次从容器中获取对象都创建全新的对象
lazy-init="true" 单例的对象默认在创建容器时候创建;
lazy-init设置为true表示第一次使用时候才创建
-->
<bean id="user" class="com.wnxy.entity.User" lazy-init="true" scope="singleton">
<property name="id" value="100"/>
<!-- public void setName(String name) {-->
<property name="name" value="Jacky"/>
</bean>
</beans>
- 创建容器测试
public class App1 {
public static void main(String[] args) {
// 创建IOC容器 = ApplicationContext + bean.xml
// 默认就会创建单例对象
ApplicationContext ac =
new ClassPathXmlApplicationContext("bean.xml");
// 从容器中获取对象
User user1 = (User) ac.getBean("user");
User user2 = (User) ac.getBean("user");
System.out.println(user1 == user2);
}
}
1.3 Spring中getBean()三种方式
-
getBean(String beanId):通过beanId获取对象
- 不足:需要强制类型转换,不灵活
-
getBean(Class clazz):通过Class方式获取对象
-
不足:容器中有多个相同类型bean的时候,会报如下错误:
expected single matching bean but found 2: stuZhenzhong,stuZhouxu
-
-
getBean(String beanId,Clazz clazz):通过beanId和Class获取对象
- 推荐使用
注意:框架默认都是通过无参构造器,帮助我们创建对象。
所以:如提供对象的构造器时,一定添加无参构造器
1.4 bean标签的属性
- bean标签
- id:bean的唯一标识
- class:定义bean的类型【class全类名】
- 子标签
- property:为对象中属性赋值【set注入】
- name属性:设置属性名称
- value属性:设置属性数值
- property:为对象中属性赋值【set注入】
1.5 BeanFactory与ApplicationContext
概述
Spring 框架带有两个 IOC 容器—— BeanFactory和ApplicationContext。BeanFactory是 IOC 容器的最基本版本,ApplicationContext扩展了BeanFactory的特性。
类结构
类关系
-
BeanFactory接口:是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。它最主要的方法就是getBean(String beanName)。
-
BeanFactory的三个核心子接口:
HierarchicalBeanFactory:提供父容器的访问功能
ListableBeanFactory:提供了批量获取Bean的方法
AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理
BeanFactory源码
public interface BeanFactory {
/**
* 用来引用一个实例,或把它和工厂产生的Bean区分开,就是说,如果一个FactoryBean的名字为a,那么,&a会得到那个Factory
*/
String FACTORY_BEAN_PREFIX = "&";
/*
* 四个不同形式的getBean方法,获取实例
*/
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
// 根据名称判断bean是否存在
boolean containsBean(String name);
// 是否为单实例Bean
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 是否为原型(多实例)
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 名称、类型是否匹配
boolean isTypeMatch(String name, Class<?> targetType)
throws NoSuchBeanDefinitionException;
// 获取类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 根据实例的名字获取实例的别名
String[] getAliases(String name);
}
延迟加载与立即加载
BeanFactory按需加载 bean,而ApplicationContext在启动时加载所有 bean。
@Test
public void test2() {
Resource res = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(res);
//只有当我们显式调用getBean()方法时,BeanFactory中定义的 bean才会被加载
factory.getBean("juice");
}
ApplicationContext以更加面向框架的风格增强了BeanFactory,并提供了一些适用于企业应用程序的特性。
- 默认初始化所有的Singleton,也可以通过配置取消预初始化。
- 继承MessageSource,因此支持国际化。
- 资源访问,比如访问URL和文件。
- 事件传播特性,即支持aop特性。
- 同时加载多个配置文件。
- 以声明式方式启动并创建Spring容器。
ApplicationContext:是IOC容器另一个重要接口, 它继承了BeanFactory的基本功能, 同时也继承了容器的高级功能,如:MessageSource(国际化资源接口)、ResourceLoader(资源加载接口)、ApplicationEventPublisher(应用事件发布接口)等。
二、Spring依赖注入
2.1 set 方法注入
(1)、实体类
User
(2)、bean2.xml
<bean id=user class="User">
<property name="User对象的属性" value="属性值"/>
</bean>
(3)、测试- junit 测试用例
第一:
<!--添加junit单元测试依赖包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!--test 表示当前jar包只在测试中有效,不会打入war包中。实际运行无效。-->
<scope>test</scope>
</dependency>
2.2 构造器注入
constructor-arg 用户构造器参数:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 构造器注入-->
<!--
constructor-arg 构造器注入
value 直接给定参数值
ref 参数值引用的是容器中的另外一个对象
index 第几个参数,从0开始
type 参数类型
name 参数名称
-->
<bean id="house" class="com.wnxy.entity.House">
<constructor-arg value="100" index="0"/>
<constructor-arg index="1" ref="str"/>
</bean>
<!--创建一个字符串,值是:1栋101房-->
<!--String str = new String("1栋101房"); -->
<bean id="str" class="java.lang.String">
<constructor-arg value="1栋101房"/>
</bean>
</beans>
2.3 p名称空间注入
注意:需要导入p名称空间
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p名称空间注入,简化property注入,也是set方法注入-->
<bean id="house" class="com.wnxy.entity.House" p:id="100" p:houseNo="1栋101房"></bean>
</beans>
2.4 对象注入
对象准备:
public class UserDao {
public void save(){
System.out.println("dao.save()");
}
}
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(){
userDao.save();
}
}
配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--先创建dao-->
<bean id="userDao" class="com.wnxy.spring.dao.UserDao"></bean>
<!--再创建service,注入dao-->
<bean id="userService1" class="com.wnxy.spring.service.UserService">
<!-- ref 表示引用容器中的另外一个bean
<property name="userDao" ref="userDao"/>
-->
<!--通过SpEL(SpringExpressionLanguage SpEL)表达式引用容器中的对象:value=#{beanId}-->
<property name="userDao" value="#{userDao}"/>
</bean>
<!--内部bean写法-->
<bean id="userService" class="com.wnxy.spring.service.UserService">
<property name="userDao">
<bean class="com.wnxy.spring.dao.UserDao"/>
</property>
</bean>
</beans>
2.5 集合注入
对象准备:
public class UserService {
// 注入集合数据
private List<String> filePaths; //-----------------
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setFilePaths(List<String> filePaths) {
this.filePaths = filePaths;
}
public void save(){
System.out.println("filePaths = " + filePaths);
userDao.save();
}
}
配置:
<!--先创建dao-->
<bean id="userDao" class="com.wnxy.spring.dao.UserDao"></bean>
<!--再创建service,注入dao-->
<bean id="userService" class="com.wnxy.spring.service.UserService">
<property name="userDao" value="#{userDao}"/>
<property name="filePaths">
<list>
<value>/root/usr/mysql</value>
<value>/root/usr/tomcat</value>
</list>
</property>
</bean>
2.6 注解注入
1.在Spring中,一个类我们为它加上注解就可以被识别为一个Bean
例如你在一个类上加上一个@Component注解,它在配置类的@ComponentScan注解扫描的包下,或者把这给个类在配置类中加上@Bean注解,那么它就被识别为Bean,加入到Spring容器里。
@Configuration
@ComponentScan("com.imooc.spring.demo")
public class SpringBeanConfiguration {
@Bean
public FirstBean firstBean() {
return new FirstBean();
}
}
2.在一个Bean中调用另外一个Bean,就需要依赖注入。
@Component
public class SecondBean {
private FirstBean firstBean;
@Autowired
public SecondBean(FirstBean firstBean) {
this.firstBean = firstBean;
}
@Override
public String toString() {
return "SecondBean{firstBean=" + firstBean + '}';
}
}
一个Bean要调用另一个Bean,直接调用是允许的,需要通过自动装配注解@Autowired进行依赖注入才能达成目的。
常用注解
注解 | 解释 |
---|---|
@Configuration | 标记的类是配置类 |
@ComponentScan(“包”) | 指定哪个包,就扫描哪个包下的注解并识别。 |
@Autowired | Bean的自动装配,可以标注在类的属性、方法及构造函数上。 |
@Component | 把普通类标记为Bean,加入到容器里,并且是单例模式。 |
@Bean | 定义一个Bean对象,加入到Spring容器里 |
@Order(数字) | 容器加载Bean的优先级,数字越小优先级越高 |
场景
我们将构造方法注入、工厂方法注入或者属性注入三种注入方式进行细化,依赖注入的方式具体如下:
- 构造方法注入Bean
- Set方法注入Bean
- 属性注入Bean
- 集合的方式注入
示例
首先通过Configuration和@ComponentScan创建一个Spring的配置类。
@Configuration
@ComponentScan("com.imooc.spring.demo.bean")//项目的包名
public class SpringBeanConfiguration {
}
新建一个类FirstBean,通过@Component注解标记为Bean,加入到Spring容器里。
@Component
public class FirstBean {
}
通过构造方法注入
@Component
public class SecondBean {
private FirstBean firstBean;
@Autowired
public SecondBean(FirstBean firstBean) {
this.firstBean = firstBean;
}
@Override
public String toString() {
return "SecondBean{firstBean=" + firstBean + '}';
}
}
通过Set方法注入
@Component
public class ThirdBean {
private FirstBean firstBean;
@Autowired
public void setFirstBean(FirstBean firstBean) {
this.firstBean = firstBean;
}
@Override
public String toString() {
return "ThirdBean{firstBean=" + firstBean + '}';
}
}
通过属性注入
@Component
public class FourthBean {
@Autowired
private FirstBean firstBean;
@Override
public String toString() {
return "FourthBean{firstBean=" + firstBean + '}';
}
}
属性注入时,private私有属性,Spring是通过反射去加载它到Spring容器里的。
通过集合注入Bean
新建一个类FifthBean,标记为Bean。 加入一个List类型 的属性,用@Autowired注入。
在配置类中对加入一个返回值为List的方法或者加两个返回String的方法,使用Bean注解,这样就完成集合的赋值。
@Component
public class FifthBean {
@Autowired
private List<String> stringList;
public List<String> getStringList() {
return stringList;
}
}
@Configuration
@ComponentScan("com.imooc.spring.demo")
public class SpringBeanConfiguration {
@Bean
public List<String> stringList() {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("imooc");
return list;
}
}
@Configuration
@ComponentScan("com.imooc.spring.demo")
public class SpringBeanConfiguration {
@Bean
public String firstString() {
return "bye";
}
@Bean
public String secondString() {
return "imooc";
}
}
第二种方式的优先级高于第一种,两种同时存在时Spring默认使用第二种,若要控制优先级要使用@Order注解来控制优先级顺序。
测试方法
class BeanDeoTest {
@Test
public void test() {
ApplicationContext applicationContext =
AnnotationConfigApplicationContext(SpringBeanConfiguration.class);
SecondBean secondBean = applicationContext.getBean("secondBean", SecondBean.class);
ThirdBean thirdBean = applicationContext.getBean("thirdBean", ThirdBean.class);
System.out.println(secondBean.toString());
System.out.println(thirdBean.toString());
}
}
ApplicationContext用来获取配置类,getBean函数用来获取指定的Bean对象。
Tips
1. 只有@ComponentScan扫描的包下的被@Component标记的类才能识别为Bean。
2. 测试时你会发现所有的FristBean对象都是一个地址,说明@Component是单例模式的。
知识对比
对比几种装配Bean的方式
-
XML注入
最原始的装配Bean的方式是XML语句,这也是Spring最早的注入方式。
<context:component-scan base-package="com.imooc.spring.demo"/>
<bean id="firstbean" class="FirstBean" />
-
代码方式注入
上文的测试类就是使用ApplicationContext进行上下文的获取,然后通过getBean进行Bean的注入。
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringBeanConfiguration.class);
SecondBean secondBean = applicationContext.getBean("secondBean", SecondBean.class);
注解注入的优点
- 简洁明了,用注解代替大量的XML配置,降低了开发成本,节省了开发量。
- 不用在.java文件和.xml文件中不断切换,提升开发的效率。
个人经验
使用统一装配规则,开发时,一般使用统一的装配规则,要么就是全部注解方式,要么就是全部XML方式。然后搭配BeanFactory 或者 ApplicationContext进行Bean的注入。非特殊情况避免注解和XMl结合使用。
推荐使用注解方式。当今互联网产品飞速迭代的情况下,成熟的互联网项目整体都是千万甚至上亿行代码,使用XML的成本会相当的高,注解已经是一种发展的趋势。
四、Spring注解使用
4.1 常用注解
注解作用:简化XML配置
创建对象相关注解:
@Component :标准一个普通的spring Bean类。 创建普通组件对象 同时@Component还是一个元注解
@Repository:标注一个DAO组件类。 创建持久化层 应用在dao层(数据访问层)。
@Service:标注一个业务逻辑组件类。 创建业务逻辑层组件 应用在service层(业务逻辑层)。
@Controller:标注一个控制器组件类。 创建控制层组件 应用在MVC层(控制层)。
DispatcherServlet会自动扫描注解了此注解的类,然后将web请求映射到注解了@RequestMapping的方法上。
这些都是注解在平时的开发过程中出镜率极高,@Component、@Repository、@Service、@Controller实质上属于同一类注解,用法相同,功能相同,区别在于标识组件的类型。 @Component可以代替@Repository、@Service、@Controller,因为这三个注解是被@Component标注的。
创建对象注解的注意点:
1、被注解的java类当做Bean实例,Bean实例的名称默认是Bean类的首字母小写,其他部分不变。@Service也可以自定义Bean名称,但是必须是唯一的!
2、尽量使用对应组件注解的类替换@Component注解,在spring未来的版本中,@Controller,@Service,@Repository会携带更多语义。并且便于开发和维护! 3、指定了某些类可作为Spring Bean类使用后,最好还需要让spring搜索指定路径,在Spring配置文件加入如下配置:
<!-- 自动扫描指定包及其子包下的所有Bean类 -->
<context:component-scan base-package=""/> ------->这个是注解扫描器
依赖注入相关注解:
@Autowired Spring提供的工具(由Spring的依赖注入工具(BeanPostProcessorBeanFactoryPostProcessor)自动注入)。可用于为类的属性、构造器、方法进行注值用于自动注入bean类型的对象,默认是按照类型自动装配,因此符合条件的对象不能超过一个,否则容器将不知道使用哪个对象,会报错。此时我们还可以通过@qualifier(“依赖的bean的id”)注解指明使用哪个对象来自动装配。
@Qualifier 配置@Autrwired一起使用;让@Autowired只根据名称注入; 一旦使用@Qualifier,不会根据类型注入了。
@Value 经常与Sping EL表达式语言一起使用,注入普通字符,系统属性,表达式运算结果,其他Bean的属性,文件内容,网址请求内容,配置文件属性值等。
该注解的作用是将我们配置文件的属性读出来,有@Value(“${}”)和@Value(“#{}”)两种方式
@Resource 注解:我们发现如果使用@autowired注解当需要指明注入的bean的id时还需要使用@qualifier注解,比较麻烦。此时我们还可以使用 @Resource 注解。@Resource注解单独使用时和@autowired效果一样,但是当需要指明注入的id时可以直接通过其name属性来指定,如,指明装配id为computer的bean时可以使用:@Resource(name=”computer”) 。 此时,@Resource注解相当于@autowired+@qualifier。
注意:
@Value的值有两类:
① ${ property : default_value }
② #{ obj.property? :default_value }
第一个注入的是外部配置文件对应的property,第二个则是SpEL表达式对应的内容。 那个
default_value,就是前面的值为空时的默认值。注意二者的不同,#{}里面那个obj代表对象。
依赖注入注解的注意点:
(1):相同点 @Resource的作用相当于@Autowired,均可标注在字段或属性的setter方法上。
(2):不同点
a :提供方 @Autowired是Spring的注解,@Resource是javax.annotation注解,而是来自于JSR-250,J2EE提供,需要JDK1.6及以上。
b :注入方式 @Autowired只按照Type 注入;@Resource默认按Name自动注入,也提供按照Type 注入;
c :属性
@Autowired注解可用于为类的属性、构造器、方法进行注值。默认情况下,其依赖的对象必须存在(bean可用),如果需要改变这种默认方式,可以设置其 required属性为false。 还有一个比较重要的点就是,
@Autowired注解默认按照类型装配,如果容器中包含多个同一类型的Bean,那么启动容器时会报找不到指定类型bean的异常,解决办法是结合@Qualifier注解进行限定,指定注入的bean名称。 顺序是先根据类型注入: 自动去ioc容器中找dao该类型的对象注入;再根据名称注入:如果该类型的对象有多个,就根据字段的名称注入;前提:该类型的对象有多个 小结:先根据类型注入;如果类型有多个,再根据字段名称注入
@Resource有两个中重要的属性:name和type。name属性指定byName,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
d:@Resource注解的使用性更为灵活,可指定名称,也可以指定类型 ;@Autowired注解进行装配容易抛出异常,特别是装配的bean类型有多个的时候,而解决的办法是需要在增加@Qualifier进行限定。
Spring整合junit单元测试
第一步:引入依赖
<dependencies>
<!-- 提供了springIOC,AOP等 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- junit的Spring测试 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
</dependencies>
<!-- 注意!: spring-context的版本要和spring-test的版本要相同 -->
- @Test:测试方法
- @Ignore:被忽略的测试方法:加上之后,暂时不运行此段代码
- @Before:每一个测试方法之前运行
- @After:每一个测试方法之后运行
- @BeforeClass:方法必须必须要是静态方法(static 声明),所有测试开始之前运行,注意区分 @Before
- @AfterClass:方法必须要是静态方法(static 声明),所有测试结束之后运行,注意区分 @After
-
@ContextConfiguration 注解:
locations 属性:用于指定配置文件的位置。如果是类路径下,需要用 classpath:表明
classes 属性:用于指定注解的类。当不使用 xml 配置时,需要用此属性指定注解类的位置。 -
@RunWith(SpringJUnit4ClassRunner.class)
-
@RunWith:用于指定junit运行环境
@ContextConfiguration:用于指定spring配置环境
// 指定配置类使用 classes 参数
@ContextConfiguration(classes = SpringConfiguration.class)
// 指定配置文件使用 locations 参数
@ContextConfiguration(locations = "classpath:applicationContext.xml")
指定初始化和销毁回调
通过注解的方式,写在特定的方法上也可以指明Bean对象的初始化和销毁的回调函数。
- @PostConstruct:写在方法上,指定此方法为初始化回调方法
- @PreDestroy:写在方法上,指定此方法为销毁的回调方法
//指定初始化的方法
@PostConstruct
public void initMethod() {
System.out.println("我是初始化方法");
}
//指定销毁之前执行的方法
@PreDestroy
public void destroyMethod() {
System.out.println("我是对象销毁之前执行的方法");
}
Spring事务模块注解
1、常用到的注解
在处理dao层或service层的事务操作时,譬如删除失败时的回滚操作。使用@Transactional 作为注解,但是需要在配置文件激活
@Transactional:表示所有类下所有方法都使用事务
@TransactionConfiguration:用于配置事务
<!-- 开启注解方式声明事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
2、举例
@Service
public class CompanyServiceImpl implements CompanyService {
@Autowired
private CompanyDAO companyDAO;
@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
public int deleteByName(String name) {
int result = companyDAO.deleteByName(name);
return result;
}
...
}
3、总结
事务的传播机制和隔离机制比较重要!
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类 似的操作 |
readOnly : 事务的读写属性,取true或者false,true为只读、默认为false
rollbackFor : 回滚策略,当遇到指定异常时回滚。譬如上例遇到异常就回滚
timeout (补充的) : 设置超时时间,单位为秒
isolation : 设置事务隔离级别,枚举类型,一共五种
类型 | 说明 |
---|---|
DEFAULT | 采用数据库默认隔离级别 |
READ_UNCOMMITTED | 读未提交的数据(会出现脏读取) |
READ_COMMITTED | 读已提交的数据(会出现幻读,即前后两次读的不一样) |
REPEATABLE_READ | 可重复读,会出现幻读 |
SERIALIZABLE 串行化 | (对资源消耗较大,一般不使用) |