Spring必知必会
本文通过总结Spring相关教学视频和面试题,从概念和实战简单的回顾了Spring学习过程,适合入门和复习。
1.概念
1.1 基本概念
1.1.1 什么是Spring
-
Spring是一个轻量级Java开发框架 。
-
目的是解决企业级应用开发的业务逻辑层和其他各层的耦合问题,即解决企业级应用开发的复杂性。
-
两个核心:控制反转(IOC)和面向切面编程(AOP)
1.1.2 Spring优点
- 方便解耦,简化开发
- 提供面向切面编程,方便实现对程序进行权限拦截、运行监控等功能
- 内部提供了对各种优秀框架的直接支持
- 降低JavaEE API的使用难度
1.2 控制反转
1.2.1 概念
-
含义:控制反转把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。即对组件对象控制权的转移,从程序代码本身转移到了外部容器。
-
作用:管理对象的创建和依赖关系的维护
-
优点:降低代码量;易于测试;降低侵入性;支持加载服务时的饿汉式初始化和懒加载。
-
依赖注入:是控制反转的实现方式,代码不直接组装你的组件和服务,而在配置文件里描述哪些组件需要哪些服务,由容器负责组装。
1.2.2 Spring IOC容器
- 作用:负责创建对象,管理对象,装配对象, 配置对象,管理对象的生命周期。
1.3 面向切面编程
- 详见第三章
2.Bean管理
2.1 xml方式
2.1.1 创建对象
-
在spring配置文件中,使用bean标签创建对象。提供对象id和类路径和类名
<bean id="ObjectName" class="package.ClassName"></bean>
2.1.2 注入基本属性
-
根据set方法,设置各变量的值
<bean id="ObjectName" class="package.ClassName"> <property name="variableName" value="value"></property> </bean>
-
根据构造器参数,设置各变量的值
<bean id="ObjectName" class="package.ClassName"> <constructor-arg name="variableName" value="value"></property> </bean>
-
使用p名称空间,结合set方法方便注入
<beans xmlns:p="http://www.springframework.org/schema/p"> <bean id="ObjectName" class="package.ClassName" p:variableName="value"></bean> </beans>
2.1.3 注入字面量
-
null
<bean id="ObjectName" class="package.ClassName"> <property name="name"><null/></property> </bean>
-
特殊符号,使用
<![CDATA[...]]>
,将特殊符号包含<bean id="ObjectName" class="package.ClassName"> <property name="name"> <value><![CDATA[<<special>>]]></value> </property> </bean>
2.1.4 注入对象
-
注入外部bean
<bean id="ObjectName" class="package.ClassName"> <property name="objectName2" ref="value"></property> </bean> <bean id="value" class="package.ClassName2"></bean>
-
注入内部bean(一个bean仅被当做另一个bean的属性)
<bean id="ObjectName" class="package.ClassName"> <property name="variableName"> <bean id="ObjectName2" class="package.ClassName2"> <property name="variableName2" value="value2"></property> </bean> </property> </bean>
-
级联赋值,即直接对关联对象的某个属性赋值,需要在本类中添加get方法返回关联对象
private AsClass asObject; public AsClass getAsClass {return asObject;}
<bean id="ObjectName" class="package.ClassName"> <property name="asObject" ref="value"></property> <property name="asObject.variableName" value="value2"></property> </bean> <bean id="value" class="package.ClassName2"></bean>
-
注入数组和集合
-
数组
<bean id="ObjectName" class="package.ClassName"> <property name="arrayName"> <array> <value>value1</value> <value>value2</value> </array> </property> </bean>
-
列表list
<bean id="ObjectName" class="package.ClassName"> <property name="listName"> <list> <value>value1</value> <value>value2</value> </list> </property> </bean>
-
映射map
<bean id="ObjectName" class="package.ClassName"> <property name="mapName"> <map> <entry key="key1" value="value1"></entry> <entry key="key2" value="value2"></entry> </map> </property> </bean>
-
集合set
<bean id="ObjectName" class="package.ClassName"> <property name="setName"> <set> <value>value1</value> <value>value2</value> </set> </property> </bean>
-
集合中设置对象,例如list
<bean id="ObjectName" class="package.ClassName"> <property name="listName"> <list> <ref bean="object1"></ref> <ref bean="object2"></ref> </list> </property> </bean> <bean id="object1" class="package.ClassName2"></bean> <bean id="object2" class="package.ClassName2"></bean>
-
2.1.5 提取集合注入
可以将注入集合的部分抽取出来,方便使用。
-
添加util名称空间
<beans xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
-
提取集合
<bean id="ObjectName" class="package.ClassName"> <property name="listName" ref="listRef"></property> </bean> <util:list id="listRef"> <value>value1</value> <value>value2</value> </util:list>
2.1.6 注入外部属性文件
-
直接配置
例如配置德鲁伊连接池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/aDatabaseName"></property> <property name="username" value="aUsername"></property> <property name="password" value="aPassword"></property> </bean>
-
通过properties文件
<!--引入context名称空间--> <beans xmlns:util="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--引入properties文件--> <context:property-placeholder location="classpath:druid.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"></property> <property name="url" value="${url}"></property> <property name="username" value="${username}"></property> <property name="password" value="${password}"></property> </bean> </beans>
2.1.7 使用对象
-
基本方法
- 代码实现
//加载配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); //获取配置文件创建的对象 ClassName objectName = context.getBean("objectName",ClassName.class); //调用方法 objectName.aMethod();
- ApplicationContext接口继承BeanFactory接口,与BeanFactory共为Spring的两大核心接口。
- ApplicationContext的实现类
类名 描述 FileSystemXmlApplicationContext 参数为相对项目根路径 ClassPathXmlApplicationContext 参数为classpath路径 WebXmlApplicationContext 用于web应用的bean -
类的作用域(scope)
-
singleton:默认,即bean在每个IOC容器中只有一个实例,在加载配置文件时就会创建单实例对象。
-
prototype:一个bean的定义可以有多个实例,在加载配置文件时不创建对象,而是在调用getbean方法返回对象时创造对象。
-
其他:request, session, global-session
-
代码实现
<bean id="ObjectName" class="package.ClassName" scope="prototype"></bean>
-
2.1.7 装配
-
装备:在Spring容器中把bean组装到一起。
-
自动装配:在Spring中,对象无需自己查找或创建关联的其他对象,而是由容器进行关联。
-
自动装配的不足:
- 基本数据类型、字面量、类字面量无法使用自动装配来注入。
- 自动装配不如显示装配精确,装配依赖中若是出现匹配到多个bean,装配将会失败。
-
自动装配类型
- byType:通过参数类型自动装配(若有多个同类型的bean会报异常)
- byName:通过bean名称进行装配(即property name与bean id匹配)
- constructor:通过构造函数的参数根据byType装配
- autodetect:自动探测,如果有构造方法,通过construct,否则使用byType。
- no:默认方式,不进行自动装配
-
代码实现
<bean id="ObjectName" class="package.ClassName" autowire="byName"></bean> <!--若上类中有一属性名为propertyName则能够自动装配--> <bean id="propertyName" class="package.ClassName2"></bean>
2.2 注解方式
2.2.1 概念
-
注解:代码特殊标记,可作用与类、方法和属性
-
作用:通过注解的帮助进行Spring配置,简化xml配置。
-
过程:
-
通过xml开启组件扫描,或创建配置类替代xml配置文件
-
在类上方添加对象注解
-
在类中需要装配的位置添加注解
-
2.2.2 组件扫描
-
作用:对某个包或类启用注解
-
基本实现:
<context:component-scan base-package="anno"></context:component-scan>
-
filter:可设置仅扫描或不扫描哪些注解
<context:component-scan base-package="anno" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
2.2.3 配置类
-
基本实现
@Configuration @ComponentScan(basePackages={"anno"}) public class SpringConfig{ }
2.2.4 对象注解
-
作用:把类标注为可以进行自动装配的类
-
类型
类型 描述 Component 将类标记为bean,是任何Spring管理组件的通用构造型 Controller 将类标记为SpringMVC控制器 Service 适用与服务层类 Repository 适用于持久层(DAO)
2.2.5 属性注入
-
类型
类型 描述 AutoWired 根据属性类型自动装配, Resource 默认按照名称装配,找不到再根据类型装配 Qualifier 当有多个同类型的bean时,与AutoWired一同使用指定名称 Value 注入普通类型 -
代码实现
@Service public class UserService { @Autowired private UserDao userDao; @Resource(name="userDaoImpl") private UserDao userDao2; @Autowired @Qualifier(value = "userDaoImpl") private UserDao userDao2; @Value(value = "valueFromAnnotation") private String name;
2.2.6 其他注解
类型 | 描述 |
---|---|
Required | 表明bean属性必须在配置的时候设置,即决定是否强制注入,通常修饰set方法。 |
Scope | 声明bean的作用域 |
2.3 bean的生命周期
2.3.1 概念
- 理解bean的生命周期可以帮助利用Spring提供的扩展点来自定义bean的创建过程。
2.3.2 过程
顺序 | 过程 | 描述 |
---|---|---|
1 | bean实例化 | Spring启动,查找并加载需要被Spring管理的bean,进行bean的实例化 |
2 | bean属性注入 | Spring将值和bean的引用注入到对应的属性 |
3 | 调用BeanNameAware.setBeanName() | 若实现该接口,将id传递给该方法 |
4 | 调用BeanFactortyAware.setBeanFactory() | 若实现该接口,将BeanFactory容器传入 |
5 | 调用ApplicationContextAware.setApplicationContext() | 若实现该接口,将bean所在应用上下文传入 |
6 | 调用BeanPostProcessor.postProcessBeforeInitialization() | 若实现该接口,调用前置处理方法 |
7 | 调用InitializingBean.afterPropertiesSet() | 若实现该接口,调用该方法 |
8 | 调用自定义初始化方法(init-method) | bean内声明的初始化方法 |
9 | 调用BeanPostProcessor.postProcessAfterInitialization() | 若实现该接口,调用后置处理方法 |
bean可以使用了,直到被应用上下文销毁 | ||
10 | 调用DisposableBean.destroy() | 若实现该接口,调用该方法 |
11 | 调用自定义销毁方法(destroy-method) | bean内声明的销毁方法 |
2.3.3 自定义方法
-
xml实现:在xml定义bean中的某个方法为初始化或销毁方法
<bean id="ObjectName" class="package.ClassName" init-method="theInitMethod" destroy-method="theDestroyMethod"></bean>
-
注解实现:在初始化和销毁方法前分别使用
@PostConstruct
和@Predestroy
。
3.面向切面编程AOP
3.1 基本概念
3.1.1 名词解释
- 连接点:指方法,是切面能够织入的位置,即能够被增强的方法。
- 切入点:切面具体织入的位置
- 通知:切面的工作,即增强的部分。
- 切面:把通知引用到切入点的过程
- 织入:将切面代码插入到目标对象的过程
3.1.2 面向切面编程
-
含义:在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想。
-
使用:把与业务无关但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块 。
-
优点:减少系统中的重复代码,降低了模块间的耦合度,提高了系统的可维护性。
-
用途:权限认证,日志,事务处理等。
3.2 动态代理
3.2.1 与AOP
-
Spring AOP基于动态代理实现
-
动态代理表明AOP框架不会修改字节码,而是每次运行时在内存中临时为方法生成一个代理对象,这个代理对象包含了目标对象的全部方法,并且在切点做了增强处理,并回调原对象的方法。
-
动态代理有JDK动态代理和CGLIB动态代理
3.2.2 JDK动态代理
-
当目标对象是基于接口实现的,AOP框架会采用JDK动态代理。
-
过程:
- 创建接口和实现类
- 通过实现InvocationHandler接口,并重写invoke方法创建代理对象
- 使用Proxy.newProxyInstance()返回增强的对象。
-
简单实现
public interface Addition { public int add(int a, int b); }
public class AdditionImpl implements Addition { @Override public int add(int a, int b) { return a + b; } }
class AdditionProxy implements InvocationHandler{ private Object obj; public AdditionProxy(Object obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("在原方法之前执行"); Object res = method.invoke(obj, args); System.out.println("在原方法之后执行"); return res; }
public class JDKProxy { public static void main(String[] args) { Class[] interfaces = {Addition.class}; Addition addition = (Addition)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new AdditionProxy(Addition)); int result = addition.add(2,3); System.out.println("result: " + result); } }
3.2.3 CGLIB动态代理
- 如果代理类没有实现接口,那么框架会选择使用CGLIB来动态代理目标类。
- CGLIB是一个代码生成的类库,在运行时生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。
3.2.4 动态代理与静态代理
- 静态代理
- 静态代理在编译阶段生成代理类,即在编译阶段将切面织入到字节码中,运行时就是增强之后的对象。
- 优点:效率高
- 代表:AspectJ
- 动态代理
- 每次运行时在内存中临时为方法生成一个代理对象
- 代表:Spring AOP
3.3 使用
3.3.1 Spring AOP与AspectJ
-
Spring AOP:通过Spring IoC提供一个简单的AOP实现,以解决常见问题。但并不是完整的AOP解决方案,它只能用于Spring容器管理的bean。只支持方法连接点。
-
AspectJ:EcLipse发起的一个面向切面的框架,AspectJ定义了AOP语法,它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。支持多种连接点。
-
AspectJ独立于Spring,但是Spring使用了AspectJ样式的注解。
3.3.2 xml与注解实现
-
在xml中打开注解扫描,开启AspectJ生成代理对象
<!--添加context和aop命名空间--> <beans xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="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="aop"></context:component-scan> <!--生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
-
创建目标对象,并添加注解
@Component public class User { public void create(){ System.out.println("Create a user."); } }
-
创建代理对象,并添加通知
@Component @Aspect public class UserProxy { @Before(value = "execution(* aop.User.create(..))") public void before(){ System.out.println("before"); } }
3.3.3 execution表达式
-
作用:用于匹配方法执行的连接点
-
完整格式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
类型 是否必填 内容 修饰符 否 public等,*表示任意 返回值类型 是 *表示所有类型 类型声明 否 名称 是 包.类.方法 参数列表 是 ()表示没有参数,(…)任意参数 异常列表 否
3.3.4 通知类型
-
五种类型
注解 类型 作用 @Before 前置通知 在目标方法执行前调用 @AfterReturning 后置通知 在目标方法执行后调用,除非抛出异常 @After 最终通知 在目标方法执行后调用 @AfterThrowing 异常通知 在目标方法异常后调用 @Around 环绕通知 在目标方法执行前后调用 -
环绕通知实现
@Around(value = "execution(* aop.User.create(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { //执行前调用 System.out.println("before around"); //执行目标方法 proceedingJoinPoint.proceed(); //执行后调用 System.out.println("after around"); }
3.3.5 其他注解
-
Pointcut
-
作用:对相同的切入点进行抽取,减少重复。
-
内容:表达式和签名(方法)
-
代码实现:
@Pointcut(value = "execution(* aop.User.create(..))") public void aPointCut(){ } @Before(value = "aPointCut()") public void before(){ System.out.println("before"); } @After(value = "aPointCut()") public void after(){ System.out.println("after"); }
-
-
Order:在代理类上使用
@order(int)
可以表示代理类的执行顺序
3.3.6 纯注解实现
-
通过创建配置类替代xml配置文件
@Configuration @ComponentScan(basePackages={"aop"}) @EnableAspectJAutoProxy(proxyTargetClass=true) public class SpringConfig{ }
3.3.7 xml实现
-
在xml中创建类对象,并配置切入点和切面
<bean id="user" class="aop.User"></bean> <bean id="userProxy" class="aop.UserProxy"></bean> <aop:config> <aop:pointcut id="aPointCut" expression="execution(* aop.User.create(..))"/> <aop:aspect ref="userProxy"> <aop:before method="before" pointcut-ref="aPointCut"/> </aop:aspect> </aop:config>
4. JDBC
4.1 概念
4.1.1 Spring JDBC
- Spring JDBC是Spring框架的模块之一,用于简化JDBC编程。
- Spring JDBC负责数据库资源管理和错误处理。开发者只需声明 SQL 语句、调用合适的 Spring JDBC框架 API、处理结果集即可。
4.1.2 JDBCTemplate
- JdbcTemplate 类是 Spring JDBC 的核心类,提供了一组操作 SQL 语句的 API。
4.2 使用
4.2.1 相关jar包
- 数据库相关:druid, mysql-connector-java
- Spring相关:spring-jdbc, spring-orm, spring-tx
4.2.2 配置文件
-
配置druid连接池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/aDatabaseName"></property> <property name="username" value="aUsername"></property> <property name="password" value="aPassword"></property> </bean>
-
将数据源注入JdbcTemplate
<bean id ="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean>
-
在DAO类中使用注解注入JdbcTemplate对象,进行增删改查等操作
4.2.3 JDBCTemplate基础操作
-
类型
方法名 返回值(参数) 描述 execute void(String sql) 一般执行数据定义语言(DDL) execute <T> T (StatementCallback<T> action) update int(String sql, Object…args) 一般执行数据操作语言(DML),返回影响的行数 batchUpdate int[](String sql, List<Object[]> batchArgs) 添加多条记录 queryForObject <T> T(String sql, RowMapper<T> rowMapper, Object…args) 查询单条数据,并使用返回数据创建对象 query <T> List<T>(String sql, RowMapper<T> rowMapper, Object…args) 查询多条数据,并使用返回数据创建对象列表 -
简单实现
//添加数据 String sql = "insert into `users` values(?,?,?)"; int update = jdbcTemplate.update(sql, user.getUserId(), user.getUsername(), user.getPassword()); //查询数据 String sql = "select count(*) from `users`"; Integer num = jdbcTemplate.queryForObject(sql,Integer.class); //通过查询返回对象 String sql = "select * from `users` where id = ?"; int id = 1; User user = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),id); //批量操作 List<Object[]> batchArgs = new ArrayList<>(); batchArgs.add(new Object[]{1,"Amy","123"}); batchArgs.add(new Object[]{2,"Bob","456"}); String sql = "insert into `users` values(?,?,?)"; int[] affected = jdbcTemplate.batchUpdate(sql,batchArgs);
4.3 事务
4.3.1 概念
-
Spring支持的事物管理类型
- 编程式事务管理:通过编程方式管理事务。灵活性强但可维护性低。
- 声明式事务管理:用注解和xml配置文件管理事务,即业务代码和事务管理分离。
-
Spring事务实现原理
- Spring并不直接管理事务,而是提供了多种事务管理器,本质其实就是数据库对事务的支持 。
- Spring事务管理器的接口是
PlatformTransactionManager
,为各个平台如JDBC、Hibernate等提供了对应的事务管理器。
-
核心接口
名称 描述 PlatformTransactionManager 按照给定的规则执行提交回滚等操作 TransactionDefinition 定义了事务属性 TransactionStatus 事务运行状态,如是否提交、是否有保存点等
4.3.2 Spring事务属性
事务属性是事务的基本配置,描述了事务策略如何应用到方法上。主要定义在TransactionDefinition
接口。
属性 | 描述 |
---|---|
传播行为(propagation behavior) | 当多事务同时存在时,Spring处理事务的行为。 主要解决业务层方法之间的相互调用的问题 |
隔离级别(isolation level) | 若干个并发的事务之间的隔离程度 |
是否超时(timeout) | 一个事务所允许执行的最长时间,超时则自动回滚事务 |
是否只读(read only) | 对事务性资源进行只读操作或者是读写操作 |
回滚规则 | 出现异常时的回滚规则 |
4.3.3 传播行为
名称 | 值 | 描述 |
---|---|---|
PROPAGATION_REQUIRED | 0 | 当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行,否则启动一个新的事务 |
PROPAGATION_SUPPORTS | 1 | 如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。 |
PROPAGATION_MANDATORY | 2 | 该方法必须在事务中运行,如果当前事务不存在,则抛出异常。 |
PROPAGATION_REQUIRES_NEW | 3 | 无论当前存不存在事务,都创建新事务。 |
PROPAGATION_NOT_SUPPORTED | 4 | 以非事务方式执行操作,如果存在当前事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 5 | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 6 | 如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与REQUIRED一样。 |
4.3.4 隔离级别
名称 | 值 | 描述 |
---|---|---|
ISOLATION_DEFAULT | -1 | 默认值,使用底层数据库的默认隔离级别 |
ISOLATION_READ_UNCOMMITTED | 1 | 读未提交。事务未提交前就可被其他事务读取(会出现幻读、脏读、不可重复读) |
ISOLATION_READ_COMMITTED | 2 | 读已提交。事务提交后才可被其他事务读取(会出现幻读和不可重复读) |
ISOLATION_REPEATABLE_READ | 4 | 可重复读。对同一字段的多次读取结果都是一致的(会出现幻读) |
ISOLATION_SERIALIZABLE | 8 | 序列化。 |
4.3.5 声明式事务管理实现
-
配置事务管理器
-
使用xml配置文件配置
<!--引入tx名称空间(此处省略其他已经引入的)--> <beans xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"> </tx:annotation-driven></tx:annotation-driven> </beans>
-
或使用配置类配置
@Configuration @ComponentScan(basePackages="jdbcTemplate") @EnableTransactionManagement public class Config { //创建数据库连接池 @Bean public DruidDataSource getDruidDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/xxxx"); dataSource.setUsername("xxx"); dataSource.setPassword("xxx"); return dataSource; } //创建JdbcTemplate对象 @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } //创建事务管理器 @Bean public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){ DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } }
-
-
事务操作
-
基于注解
@Service @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ) public class UserService { @Autowired private UserDao userDao; public void transfer(){ userDao.out(); userDao.in(); } }
-
或使用xml
<!-- 配置事务通知 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <!-- 配置切入点 --> <aop:pointcut expression="execution(* jdbcTemplate.*(..))" id="pointCut"/> <!-- 配置切面 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointCut"/> </aop:config>
-