Spring
0. 两个特点
1. 控制反转 (IOC)
2. 面向切面编程(AOP)
1. IOC(Inversion of Control)
IOC 的底层原理
-
把对象的创建和对象的调用,交给Spring进行管理
-
降低耦合度
IOC的过程
1.1xml 方式
-
xml配置文件, 创建对象的xml
-
创建工厂类(反射创建对象)
-
class UserFactoy { public static UserDao getDao() { String classVal = ""//XML解析 //反射创建对象 Class clazz = Class.forName(classVal); (/*强转*/)clazz.newInstance(); } }
-
IOC基于IOC容器,两个接口
-
BeanFactory
IOC最基本的, Spring 内部接口, 一般我们不用
-
ApplicationContext
是BeanFactory的子接口, 提供了更多的功能, 一般我们用这个
(1) 加载配置文件的时候, 就会去创建
(2)把耗时的过程放在服务器启动的时候去搞, 所以我们喜欢用这个
实现类
ClassPathXmlApplication
FileSystemXmlApplication
-
-
IOC操作
-
Bean管理
-
Spring创建对象
-
Spring注入属性
-
-
Bean操作
-
XML配置文件
-
<bean id="xxx", class="全类名"></bean> <!--属性--> <!--id:唯一属性 给对象起别名 getBean()的时候第一个参数--> <!--class:全类名--> <!--name 属性,和id 属性一样--> <!-- 注意调用的是无参构造器-->
-
public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("xml的文件"); Object obj = context.getBean("id属性值", 类名.class);//创建对象 //这样就创建好了对象 }
基于XML注入属性
-
set方法
-
<bean id="" class="" > <property name="" value=""></property> </bean>
-
构造方法
-
<constructor-arg name="" value=""></constructor-arg> <!-- 如果有多个属性,可以写多行 -->
-
-
XML注入其他属性,可以为null
<property name="" > <null/> </property>
-
p名称空间注入
-
xmlns:p = "http://www.springframework.org/schema/beans" <bean id="" class="" p:属性名="" ...> </bean>
-
写特殊符号
-
<porperty name="" value="<hh>"> <!-- 注入<> -->
-
-
<property name="">
<value><![CDATA[<<xxx>>]]></value>
</property>
外部bean
poublic interface UserDao {
void update();
}
public class UserDao implements UserDao{
public void update() {
//xxx
}
}
public interface UserService {
void update();
}
public class UserServiceImpl implements UserService {
/*
原始做法
UserDao userDao = new UserDaoImpl
UserDao userDao = new UserDaoImpl
public void update() {
userDao.update();
}
*/
private UserDao usreDao;//属性值
//set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
<!--
创建userService UserDao是他的属性值
-->
<bean id="userService" class="com.service.UserService">
<!-- ref 引用下边创建的对象-->
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.dao.UserDaoImpl"></bean>
内部bean和级联赋值
-
级联赋值(也就是外部bean ref)
-
<bean id="emp" class="com.bean.Emp"> <property name="eName" value="lang"></property> <property name="gender" value="boy"></property> <property name="dept" ref="dept"> </property> </bean> <!--属性dept是一个类 也可以用上边的外部bean, ref的方法--> <bean id="dept" class="com.bean.Dept"> <property name="dName" value="财务部"></property> </bean>
-
一对多的关系
-
<bean id="emp" class="com.bean.Emp"> <property name="eName" value="lang"></property> <property name="gender" value="boy"></property> <property name="dept"> <!--属性dept是一个类 也可以用上边的外部bean, ref的方法--> <bean id="dept" class="com.bean.Dept"> <property name="dName" value="财务部"></property> </bean> </property> </bean>
-
注入集合属性
-
注入数组
-
<property name="courses" > <array> <value>语文</value> <value>数学</value> <value>英语</value> </array> </property>
-
注入List集合
-
<property name="list"> <list> <value>lang</value> <value>浪</value> <value>梓</value> </list> </property>
-
注入Map集合
-
<property name="map"> <map> <entry key="java" value="hard"></entry> </map> </property>
-
-
在集合设置对象类型的值
<bean id="" class=""> <property name="list"> <list> <ref bean="id01"> </ref> <ref bean="id02"> </ref> </list> </property> </bean> <bean id="id01" class=""></bean> <bean id="id02" class=""></bean>
-
把集合注入部分提取出来
-
(1) 引入名称空间 util
-
(2) 注入 ref
-
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <util:list id="bookList"> <value>java</value> <value>cpp</value> <value>spring</value> </util:list> <bean id="book" class="com.collection.Book"> <property name="list" ref="bookList"> </property> </bean> </beans>
-
IOC操作bean的管理
-
普通bean: 定义的和返回的是一个类型
-
工厂bean :不一定是一个类型
-
(1) 实现FactoryBean接口
-
(2)在接口方法中定义返回类型
-
public interface FactoryBean<T> {
String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
}
bean的作用域
-
bean可以是多实例也可以是多实例(创建对象时,创建的是同一个对象?)
-
如何设置, bean标签 scope属性
-
<bean scope="singleton"><!-- 单实例 加载配置文件的时候, 会创建单实例对象 --> <bean scope="prototype"> <!-- 多实例 调用getBean()时会创建对象 -->
bean的生命周期
-
通过无参构造器创建实例
-
为bean设置属性
-
调用bean初始化方法 initMethod xml中配置
-
bean可以使用了
-
当容器关闭时, 调用bean销毁的方法 destroyMethod xml中配置
bean的后置处理器
-
在第三步前后各有一个 把bean的实例传递后置处理器, 所以一共七步
xml的自动装配
不需要写==property==标签把属性注入
<bean autowire="byName"></bean>
<!--根据属性名字-->
<bean autowire="byType"></bean>
<!--根据属性类型-->
引入外部属性文件
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/test"></property>
<property name="username" value="root"></property>
<property name="password" value="990808"></property>
</bean>
引入外部==properties==文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=990808
xml引入context
-
利用context:property-placeholder 的location属性读取properties文件
-
property 标签利用表达式${}注入属性值
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<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>
1.2 注解方式
使用注解可以简化xml配置
- 创建对象的注解
-
@Component
-
@Service
-
@Controller
-
@Repository
-
流程
-
xml配置
context的名称空间
开启组件扫描, 扫描的包(==扫描多个包时, 可以用逗号隔开,或者可以直接写上一级的目录==)
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 开启组件扫描--> <context:component-scan base-package="com.dao, com.service"></context:component-scan> </beans>
-
在类上写注解
@Component(value = "userService")//类似于bean标签的 id属性 public class UserService { public void add() { System.out.println("add..."); } }
细节
<context:component-scan base-package="com.dao, com.service" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!-- use-default-filters 属性 是否按照默认的方式扫描 context:include-filte 只扫描Controller的注解 context:exclude-filter 只扫描不包含Controller的注解--> </context:component-scan> <context:component-scan base-package="com.dao, com.service" use-default-filters="true"> <context:exclude-filter type="annotation" expression=""/> </context:component-scan>
注解方式注入属性
-
@Autowired 根据属性类型
-
@Qualifier 根据属性名称, 需要和Autowired一块使用
-
@Resource 以上两者都可以
-
@Value 注入普通类型
纯注解开发
-
创建配置类
类上加注解, 还有(组件扫描的设置)扫描的类设置
@Configuration @ComponentScan(basePackages = {"com"}) public class SpringConfig { }
-
创建对象的过程稍有改变
使用==AnnotationConfigApplicationContext==
public void test01() { ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService", UserService.class); }
2.AOP(Aspect Oriented Programming)
2.1 基本概念
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性同时提高了开发的效率
面向切面编程, 可以降低耦合度
2.2 底层原理
-
AOP底层使用动态代理
- 有接口 JDK的动态代理
-
创建interface
-
创建实现实现上述interface的类
-
创建代理类
-
-
没有接口的 CGLIB动态代理
- 有接口 JDK的动态代理
-
AOP的术语
-
连接点
类里边可以增强的方法
-
切入点
实际被真正增强的方法
-
通知(增强)
实际增强的逻辑部分
-
前置通知
-
后置通知
-
环绕通知
-
异常通知
-
最终通知
-
-
切面
是动作:把通知应用到切入点的过程
-
-
AOP操作(注解实现)
-
基于==AspectJ==实现
-
什么是AspectJ
单独的框架,基于xml和基于注解
-
-
引入依赖
-
切入点表达式
-
知道对哪个类的哪个方法增强
-
execution([权限修饰符] [返回类型] [全类名] [方法名] [参数列表])
-
-
-
操作步骤
-
创建被增强类, 方法
@Component public class User { public void add() { System.out.println("user add...."); } }
-
创建增强的类, 方法
@Component//创建对象 @Aspect//aop public class UserProxy { //配置通知类型 //前置通知 @Before(value = "execution(* com.aopanno.User.add(..))") public void before() { System.out.println("before...."); } //在方法返回值之后执行 @AfterReturning(value = "execution(* com.aopanno.User.add(..))") public void afterReturning() { System.out.println("AfterReturning"); } //后置, 方法执行后执行 @After(value = "execution(* com.aopanno.User.add(..))") public void after() { System.out.println("after"); } //异常 @AfterThrowing(value = "execution(* com.aopanno.User.add(..))") public void afterThrowing() { System.out.println("AfterThrowing"); } //环绕, 方法执行之前之后都执行 @Around(value = "execution(* com.aopanno.User.add(..))") public void around() { System.out.println("Around"); } }
-
在增强的类上加注解==@Aspect==
-
在增强的方法上边加上通知的注解(如前置通知 @Before(value="execution(.....)"))
-
spring配置文件
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd 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="com.aopanno"></context:component-scan> <!--开启AspectJ 生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
-
-
公共切入点提取
-
//配置通知类型 //前置通知 @Before(value = "pointCut()") public void before() { System.out.println("before...."); } //在方法返回值之后执行 @AfterReturning(value = "pointCut()") public void afterReturning() { System.out.println("AfterReturning"); } //后置, 方法执行后执行 @After(value = "pointCut()") public void after() { System.out.println("after"); } //异常 @AfterThrowing(value = "pointCut()") public void afterThrowing() { System.out.println("AfterThrowing"); } //环绕, 方法执行之前之后都执行 @Around(value = "pointCut()") public void around() { System.out.println("Around"); } //切入点抽取 @Pointcut(value = "execution(* com.aopanno.User.add(..))") public void pointCut() { }
-
-
多个增强类对同一个方法增强, 需要设置执行优先级
-
在增强类的上边添加注解@Order(数值) 数值越小,优先级越高
-
-
配置文件操作
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="book" class="com.aopxml.Book"> </bean> <bean id="bookProxy" class="com.aopxml.BookProxy"> </bean> <!-- 配置aop增强--> <aop:config> <!-- 配置切入点--> <aop:pointcut id="p" expression="execution(* com.aopxml.Book.add(..))"/> <!-- 配置切面--> <aop:aspect ref="bookProxy"> <!--这个p就是上边的id属性值--> <aop:before method="before" pointcut-ref="p"/> </aop:aspect> </aop:config> </beans>
-
完全注解方式(需要配置类)
@Configuration @ComponentScan(basePackages = {"com.aopanno"}) @EnableAspectJAutoProxy(exposeProxy = true) public class ConfigAop { }
3.JdbcTemplate
3.1 操作
-
dao层与数据库连接, service 与到层连接, 所以在dao层注入jdbcTemplate, 在service注入dao
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 组件扫描-->
<context:component-scan base-package="com"></context:component-scan>
<!-- properties文件目录-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--druid获取连接的-->
<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>
<!-- 创建jdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
-
dao层
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;//创建对象
}
-
service层
@Service
public class UserService {
@Autowired
private UserDao userDao;
}
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=990808
==spring不要写username==
下边是对一条记录的CRUD的相应方法
@Repository
public class UserDaoImpl implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;//创建对象
@Override
public void add(User user) {
String sql = "insert into user values(?,?,?,?,?)";
int update = jdbcTemplate.update(sql, user.getId(),user.getName(), user.getPassword(), user.getAddress(), user.getPhone());
System.out.println("userDao" + update);
}
@Override
public User queryById(Integer id) {
String sql = "select * from user where id=?";
return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), id);
}
@Override
public List<User> queryForList() {
String sql = "select * from user";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));
}
@Override
public int findCount() {
String slq = "select count(*) from `user`";
return jdbcTemplate.queryForObject(slq, Integer.class);
}
}
==批量insert==, (update, delete 同理)
@Override
public void batchAdd(List<Object[]> users) {
String sql = "insert into user values(?,?,?,?,?)";
jdbcTemplate.batchUpdate(sql, users);
}
4. 事务(Transaction)
4.1 基本概念
指的是数据库操作的基本单元,逻辑上是一组操作,要么都成功,要么都失败,事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
4.2 特性(ACID)
-
原子性(atomicity)
一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
-
一致性(consistency)
事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
-
隔离性(isolation)
一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
-
持久性(durability)
持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
4.3 Spring事务管理的操作
-
一般加在service层上,有两种方式,编程方式和声明式(主要使用)
-
声明式的管理方式
-
注解(使用)
-
xml配置文件
-
底层使用了AOP
-
API
interface platformTranscationManager
4.4 注解方式实现事务管理
-
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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 组件扫描--> <context:component-scan base-package="com"></context:component-scan> <!-- properties文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!-- dataSource对象--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"></property> <property name="url" value="${jdbc.url}"></property> <property name="username" value="${jdbc.username}"></property> <property name="password" value="${jdbc.password}"></property> </bean> <!-- jdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!-- 数据源--> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 创建事务管理--> <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> </beans>
-
在service添加注解
@Service @Transactional//可以加到类上也可以加到方法上 public class UserService { @Autowired private UserDao userDao; public void account(UserTable userTable) { userDao.add(userTable); userDao.reduce(userTable); } }
-
细节
- propagation事务的传播行为
-
==PROPAGATION_REQUIRED==:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这是最常见的选择,也是Spring默认的事务传播行为。(required需要,没有新建,有加入)
-
PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。(supports支持,有则加入,没有就不管了,非事务运行)
-
PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。(mandatory强制性,有则加入,没有异常)
-
==PROPAGATION_REQUIRES_NEW==:创建新事务,无论当前存不存在事务,都创建新事务。(requires_new需要新的,不管有没有,直接创建新事务)
-
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。(not supported不支持事务,存在就挂起)
-
PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。(never不支持事务,存在就异常)
-
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。(nested存在就在嵌套的执行,没有就找是否存在外面的事务,有则加入,没有则新建)
-
-
事务的隔离级别
三个并发问题
-
脏读(==接受不了==)
-
一个未提交的事务读取到了另一个未提交的事务的数据
-
A事务正在修改数据但未提交,此时B事务去读取此条数据,B事务读取的是未提交的数据,A事务回滚。B事务读的内容就是临时且无效的
-
-
不可重复读(正常)
-
一个未提交的事务读到了一个已经提交的事务
-
A事务读了一个字段,B事务更新了,然后提交了, 之后A 事务再一次读同一个字段, 值就不一样了。
-
-
幻读()
-
一个未提交的事务读到了一个已经提交的事务
-
在同一事务中两次相同查询数据的条数不一致,例如第一次查询查到5条数据,第二次查到8条数据,这是因为在两次查询的间隙,另一个事务插入了3条数据
-
隔离级别
-
**READ UNCOMMITTED **
读未提交, 以上三种问题都没解决
-
**READ COMMITTED **
读已提交 解决了脏读
-
REPEATABLE READ ==MySQL默认==
可重复读 解决了脏读 不可重复读
-
SERILIZABLE
串行化 解决了三个问题
配置隔离级别
@Transactional(propagation = Propagation.REQUIRED, isolation= Isolation.READ_UNCOMMITTED)//可以加到类上也可以加到方法上
-
timeout 超时
事务需要在一定的时间内提交, 不然会rollback
-
readOnly
读:查询操作, 写:添加修改删除操作
默认值是 false
-
rollbackFor
设置出现哪些异常进行事务的回滚
-
noRollBack
设置出些哪些异常不进行事务的回滚
- propagation事务的传播行为
@Transactional(readOnly = false, timeout = -1, propagation = Propagation.REQUIRED, isolation= Isolation.READ_UNCOMMITTED)//可以加到类上也可以加到方法上
4.5 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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 组件扫描-->
<context:component-scan base-package="com"></context:component-scan>
<!-- properties文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- dataSource对象-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- jdbcTemplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- 数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 创建事务管理-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 引入数据源-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置通知-->
<tx:advice id="txadvice">
<!-- 配置事务参数-->
<tx:attributes>
<tx:method name="account" propagation="REQUIRED" isolation="READ_COMMITTED"/>
</tx:attributes>
</tx:advice>
<aop:config >
<!-- 配置切面-->
<aop:pointcut id="pt" expression="execution(* com.service.UserService.*(..))"/>
<!-- 配置切入点-->
<aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>
4.5完全注解
配置类
@Configuration//配置类
@ComponentScan(basePackages = "com")//组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {
//数据源, 连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("990808");
return dataSource;
}
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
// ioc容器中找到DataSource类型,然后完成注入
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
// 创建事务管理对象
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager =
new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}