轻量级开源的 JavaEE 框架。解决企业开发应用的复杂性。
Spring的核心部分:
特点:
版本:5.2.6
依赖:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>5.2.8.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.8.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.2.8.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-expressionartifactId>
<version>5.2.8.RELEASEversion>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
<version>1.2version>
dependency>
demo01:创建普通类
public class User {
public void add(){
System.out.println("add...");
}
}
在 resources
目录下创建bean1.xml
文件:
<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="user" class="com.pyd.User"> bean>
beans>
进行测试代码编写:
@Test
public void testAdd() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
// 获取id为user的类
User user = context.getBean("user", User.class);
System.out.println(user);
// 调用方法
user.add();
}
getBean方法的Bean是什么?
官方的解释是 Spring Bean是事物处理组件类和实体类(POJO)对象的总称,是能够被实例化、能够被spring容器管理的java对象。可以把bean看做是一个组件,这个组件用来具体实现某个业务功能。总结性的讲,Bean就是由IOC容器初始化、装配及管理的对象,除此之外,和程序中的其他对象没有区别。简单来说,就是Java对象,但是能够被Spring容器管理。
控制反转:
底层原理:
IOC 的过程:
二者区别:是否在加载配置文件时,创建对象。
ApplicationContext 的实现类
绝对路径和类路径的区别
Bean 管理:
Bean 管理的两种方式:
创建对象
使用 bean 标签,在标签中添加属性,创建对象,常用属性:
创建对象时,默认执行无参方法
注入属性
DI:依赖注入(Dependency Injection),是IOC的另一种表述方式,即组件以一些预先定义好的方式(如:getter方法)来接收来自容器的资源注入,即注入属性
public class Book {
String author;
String title;
public void setAuthor(String author) {
this.author = author;
}
public void setTitle(String title) {
this.title = title;
}
}
<bean id="book" class="com.pyd.Book">
<property name="author" value="张浩瀚">property>
<property name="title" value="武汉理工优秀学生">property>
bean>
使用 p 名称空间注入(需要有 set 方法):
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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="book"
class="com.pyd.Book"
p:author="张浩瀚"
p:title="武汉理工优秀学生"
>
bean
>beans>
public class Order {
String name;
String id;
public Order(String name, String id) {
this.name = name;
this.id = id;
}
}
在 xml 中配置:
<bean id="order" class="com.pyd.Order">
<constructor-arg index="0" value="电脑" />
<constructor-arg name="id" value="1" />
bean>
<property name="address">
<null/>
property>
转义:
<property name="address" value="<>">
property>
CDATA:
<property>
<value> >]]> value>
property>
public interface UserDao {
public void update();
}
public class UserDaoImp implements UserDao {
@Override
public void update() {
System.out.println("userDaoImp update() called");
}
}
public class User {
private UserDao userDao;
public void setUserDao(UserDaoImp userDao) {
this.userDao = userDao;
}
public void test() {
this.userDao.update();
}
}
<bean id="userSvc" class="com.pyd.service.User">
<property name="userDao" ref="userDaoImp" />
bean>
<bean id="userDaoImp" class="com.pyd.dao.UserDaoImp" />
一对多的关系:部门和员工
一个部门有多个员工,一个员工属于一个部门。
创建 emp 和 dept 类
public class Dept {
String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "dept{" +
"name='" + name + '\'' +
'}';
}
}
public class Emp {
String name;
String gender;
Dept dept;
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
方式一:
<bean id="emp" class="com.pyd.bean.Emp">
<property name="name" value="张浩瀚" />
<property name="gender" value="男" />
<property name="dept">
<bean id="dept" class="com.pyd.bean.Dept">
<property name="name" value="帅哥部" />
bean>
property>
bean>
方式二:级联赋值
<bean id="emp" class="com.pyd.bean.Emp">
<property name="name" value="张浩瀚" />
<property name="gender" value="男" />
<property name="dept" ref="dept"> property>
bean>
<bean id="dept" class="com.pyd.bean.Dept">
<property name="name" value="帅哥部" />
bean>
需要 get 方法的写法:
<bean id="emp" class="com.pyd.bean.Emp">
<property name="name" value="张浩瀚" />
<property name="gender" value="男" />
<property name="dept" ref="dept" />
<property name="dept.name" value="大帅哥部" />
bean>
<bean id="dept" class="com.pyd.bean.Dept"/>
集合类型属性的创建:
public class Stu {
private String[] courses;
private List<String> list;
private Map<String, String> map;
private Set<String> set;
public void setSet(Set<String> set) {
this.set = set;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
}
<property name="courses">
<array>
<value>1value>
<value>2value>
<value>3value>
array>
property>
<property name="list">
<list>
<value>1value>
<value>2value>
<value>3value>
list>
property>
<property name="map">
<map>
<entry key="zhh" value="天下第一帅" />
map>
property>
<bean id="course1" class="com.pyd.bean.Course">
<property name="name" value="张浩瀚帅哥入门课上" />
<property name="id" value="1" />
bean>
<bean id="course2" class="com.pyd.bean.Course">
<property name="name" value="张浩瀚帅哥入门课下" />
<property name="id" value="2" />
bean>
<property name="courseList">
<list>
<ref bean="course1" />
<ref bean="course2" />
list>
property>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
beans>
<util:list id="bookList">
<value>book1value>
<value>book2value>
util:list>
<bean name="book" class="com.pyd.bean.Book">
<property name="books" ref="bookList" />
bean>
public class MyBean implements FactoryBean {
}
@Override
public Object getObject() throws Exception {
Course course = new Course();
course.setName("张浩瀚");
return course;
}
<bean id="myBean" class="com.pyd.factoryBean.MyBean">bean>
创建的对象,默认是单实例。(比较地址是否相同)
设置多实例对象:
scope 属性:
<bean id="myBean" class="com.pyd.factoryBean.MyBean" scope="prototype">bean>
从对象创建到销毁的过程
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
context.close();
1. 无参构造
2. 设置name
3. 执行初始化方法
4. 获取到了bean对象
5. 销毁对象方法执行
后置处理器:
<bean name="myPostBean" class="com.pyd.factoryBean.MyBeanPost">bean>
无参构造
设置name
bean后置处理器 postProcessBeforeInitialization
执行初始化方法
bean后置处理器 postProcessAfterInitialization
获取到了bean对象
销毁对象方法执行
实际工作中,用得很少
自动装配:根据装配规则(属性名称或类型),Spring 自动将匹配的属性值注入。
autowire 属性:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/fruitdb" />
<property name="username" value="root" />
<property name="password" value="zhanghaohanzuishuai" />
bean>
数据库文件jdbc.property
:
username=root
password=zhanghaohanzuishuai
url=jdbc:mysql://localhost:3306/fruitdb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
driverClass=com.mysql.cj.jdbc.Driver
引入 context 名称空间:
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>
beans>
引入外部属性文件:
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClass}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
bean>
依赖:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>5.2.8.RELEASEversion>
dependency>
功能相同
扫描多个包:用逗号分隔
扫描包上层目录
<context:component-scan base-package="com.pyd.aop">context:component-scan>
注解的 value 默认是类的名称,首字母小写。
@Component("userService")
public class UserService {
public void add() {
System.out.println("user add");
}
}
<context:component-scan base-package="com.atguigu" use-default- filters="false">
<context:include-filter
type="annotation"
expression="org.springframework.stereotype.Controller"
/>
context:component-scan>
<context:component-scan base-package="com.atguigu">
<context:exclude-filter
type="annotation"
expression="org.springframework.stereotype.Controller"
/>
context:component-scan>
接口对象:
public interface UserDao {
public void print();
}
接口实现类:
@Repository
public class UserDaoImp implements UserDao {
@Override
public void print() {
System.out.println("userDaoImp print");
}
}
@Component("userService")
public class UserService {
@Autowired
private UserDao userDao;
public void add() {
System.out.println("user add");
userDao.print();
}
}
场景:一个接口有多个实现类
需要和 Autowired 一起使用
@Repository("userDaoImp1")
public class UserDaoImp1 implements UserDao {
@Override
public void print() {
System.out.println("userDaoImp1 print");
}
}
根据名称进行注入:
@Autowired
@Qualifier("userDaoImp1")
private UserDao userDao;
Resource:根据类型注入或根据名称注入(javax 包中)
根据类型注入:
@Resource
根据名称注入:
@Resource("userService")
@Value(value = "zhh")
public String name;
不使用配置文件,完全使用注解的方式。
@Configuration:作为配置类
@ComponentScan: 需要扫描的包路径
@Configuration
@ComponentScan(basePackages = {"com.pyd.aop"})
public class SpringConfig {
}
AnnotationConfigApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
基于 Java 的主要 AOP 实现有:AspectJ Spring AOP JBoss AOP
有两种情况的动态代理:
(1)有接口:使用 JDK 动态代理
创建 UserDao 接口实现类代理对象,增强类的方法
(2)无接口:使用 CGLIB 动态代理
创建子类。
CGLIB:创建当前类子类的代理对象
使用 Proxy 类的方法创建类的代理对象。
调用 newInstance 方法:
public interface UserDao {
public int add(int a, int b);
public String update(int id);
}
public class UserDaoImp implements UserDao {
@Override
public int add(int a, int b) {
System.out.println(a + b);
return 0;
}
@Override
public String update(int id) {
return null;
}
}
public class JDKProxy {
public static void main(String[] args) {
UserDaoImp userDaoImp = new UserDaoImp();
Class[] interfaces = {UserDao.class};
new UserDaoImp();
UserDao proxy = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoImp));
proxy.add(10, 20);
}
}
class UserDaoProxy implements InvocationHandler {
public Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法执行之前");
System.out.println("method.getName() = " + method.getName());
// 增强方法执行
Object res = method.invoke(obj, args);
System.out.println("方法执行之后");
return res;
}
}
连接点:类中可以被增强的方法
切入点:实际真正被增强的方法
通知(增强):实际增强的逻辑部分。
通知有多种类型:
切面:将通知应用到切入点的过程。
导入相关 Jar 包:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.2.0.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.6.8version>
dependency>
<dependency>
<groupId>aopalliancegroupId>
<artifactId>aopallianceartifactId>
<version>1.0version>
dependency>
<dependency>
<groupId>net.sourceforge.cglibgroupId>
<artifactId>com.springsource.net.sf.cglibartifactId>
<version>2.2.0version>
dependency>
不是 Spring 的组成部分,独立的 AOP 框架,一般将 AspectJ 和 Spring 框架一起使用。
作用:知道对哪个类和哪个方法来增强。
语法结构:
execution([权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]))
例:
举例 1:对 com.micah.dao.BookDao 类里面的 add 进行增强
execution(\* com.atguigu.dao.BookDao.add(..))
举例 2:对 com.micah.dao.BookDao 类里面的所有的方法进行增强
execution(_ com.atguigu.dao.BookDao._ (..))
举例 3:对 com.atguigu.dao 包里面所有类,类里面的所有的方法进行增强
execution(_ com.micah.dao._.\* (..))
public class User {
public void add() {
System.out.println("user add");
}
}
创建不同方法,代表不同的通知类型
public class UserProxy {
public void before() {
System.out.println("前置通知");
}
}
进行通知的配置
(1)在 spring 配置文件中,开启注解扫描
<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.pyd.aop"
>context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>
(2)使用注解创建 User 和 UserProxy 对象
@Component
(3)在增强类上添加注解 Aspect
@Aspect
(4)开启 ApsectJ 生成代理对象
配置不同类型的通知
添加通知的注解,填写切入点表达式:
@Component
@Aspect
public class UserProxy {
@Before(value = "execution(* com.pyd.aop.annotation.User.add(..))")
public void before() {
System.out.println("before 前置通知");
}
@AfterReturning(value = "execution(* com.pyd.aop.annotation.User.add(..))")
public void afterReturning() {
System.out.println("afterReturning 后置通知(返回通知)");
}
@After(value = "execution(* com.pyd.aop.annotation.User.add(..))")
public void after() {
System.out.println("after 最终通知");
}
@AfterThrowing(value = "execution(* com.pyd.aop.annotation.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing 异常通知");
}
@Around(value = "execution(* com.pyd.aop.annotation.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知前");
proceedingJoinPoint.proceed();
System.out.println("环绕通知后");
}
}
Pointcut
@Pointcut(value = "execution(* com.pyd.aop.annotation.User.add(..))")
public void pointDemo() {
}
@Before(value = "pointDemo()")
public void before() {
System.out.println("before 前置通知");
}
在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高:
@Component
@Aspect
@Order(1)
public class PersonProxy
在 spring 配置文件中配置切入点:
<aop:config>
<aop:pointcut
id="p"
expression="execution(*
com.atguigu.spring5.aopxml.Book.buy(..))"
/>
<aop:aspect ref="bookProxy">
<aop:before method="before" pointcut-ref="p" />
aop:aspect>
aop:config>
@Configuration
@ComponentScan(basePackages = {"com.pyd.annotation"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
class SpringAspectConfig {
}
Spring 框架中提供的一个对象,是对原始 JDBC API 对象的简单封装。
其他操作模板类:
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.22version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.4version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.2version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.3.2version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>5.3.2version>
dependency>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
>
beans>
创建数据库连接池:
<context:property-placeholder location="classpath:jdbc.properties" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClass}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
bean>
创建 JdbcTemplate 对象:
<bean id="jdbctemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource">property>
bean>
开启组件扫描:
<context:component-scan base-package="com.atguigu">context:component-scan>
public interface BookDao {}
注入配置文件中的 JdbcTemplate 对象
@Repository
public class BookDaoImp implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
}
@Service
public class BookService {
@Autowired
private BookDao bookDao;
}
数据库:
SELECT * FROM t_fruit;
CREATE DATABASE dbtest;
USE dbtest;
CREATE TABLE book(
id int,
name VARCHAR(128),
status BOOLEAN
);
public class Book {
private int id;
private String name;
private boolean status;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setStatus(boolean status) {
this.status = status;
}
}
@Repository
public class BookDaoImp implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Book book) {
String sql = "insert into book values(?,?,?);";
Object[] args = {book.getId(), book.getName(), book.isStatus()};
int update = jdbcTemplate.update(sql, args);
System.out.println(update);
}
}
@Service
public class BookService {
@Autowired
private BookDaoImp bookDao;
public void add(Book book) {
bookDao.add(book);
}
}
查询表有多少条记录
@Override
public int count() {
String sql = "select count(*) from book";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
return count;
}
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)
参数 2:RowMapper,接口,返回不同类型的数据
查询图书的详细信息
@Override
public Book getBook(int id) {
String sql = "select * from book where id = ?";
return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<Book>(Book.class), id);
}
查询图书列表:
@Override
public List<Book> getBooksList() {
String sql = "select * from book";
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Book>(Book.class));
}
betchUpdate
@Override
public void batchAdd(List<Object[]> books) {
String sql = "insert into book values (?,?,?);";
jdbcTemplate.batchUpdate(sql, books);
}
List<Object[]> books = new ArrayList<>();
Object[] book1 = {3, "zhanghh", false};
Object[] book2 = {4, "zhangh", false};
Object[] book3 = {5, "zhanhh", false};
books.add(book1);
books.add(book2);
books.add(book3);
bookService.batchAdd(books);
数据库操作的基本单元,逻辑上一组的操作,要么都成功,要么都失败。
四个特性(ACID):
CREATE TABLE user
(
id INT,
name VARCHAR(128),
money INT
);
INSERT INTO user VALUES (1,'张浩瀚',200),(2,'章帅',300);
dao:
public interface UserDao {
public void add(int money);
public void reduce(int money);
}
@Repository
public class UserDaoImp implements UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(int money) {
System.out.println("id=1 : -" + money);
String sql = "update user set money-? where id=?";
jdbcTemplate.update(sql, money, 1);
}
@Override
public void reduce(int money) {
System.out.println("id=2 : +" + money);
String sql = "update user set money+? where id=?";
jdbcTemplate.update(sql, money, 2);
}
}
service:
@Service
public class UserService {
@Autowired
private UserDaoImp userDao;
public void transfer() {
userDao.add(100);
userDao.reduce(100);
}
}
int i = 10/0;
事务操作过程:
开启事务操作
捕获异常
出现异常,回滚
将事务加到 Service 层上
在 spring 进行事务管理操作:编程式事务管理和声明式事务管理
在 Spring 进行声明式事务管理,底层使用 AOP 原理
相关 API
接口:事务管理器,该接口针对不同框架提供不同实现类
<bean
id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
>
<property name="dataSource" ref="dataSource" />
bean>
引入名称空间:tx
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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
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"
>
开启事务注解:
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
Transactional:
当一个事务的方法被另一个事务方法调用时,该事务方法如何进行
事务传播行为:
传播行为 | 描述 |
---|---|
PROPAGATION_REQUIRED | Spring 默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行 |
PROPAGATION_REQUES_NEW | 该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可 |
PROPAGATION_SUPPORT | 如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务 |
PROPAGATION_NEVER | 如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务 |
PROPAGATION_NOT_SUPPORT | 该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码 |
PROPAGATION_MANDATORY | 与 NEVER 相反,如果外层没有事务,则抛出异常 |
PROPAGATION_NESTED | 该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。 |
传播规则回答了这样一个问题:一个新的事务应该被启动还是被挂起,或者是一个方法是否应该在事务性上下文中运行。
事务隔离级别 isolation
多事务之间不会产生影响。
不考虑隔离性会出现三个读问题:
通过设置隔离级别来解决读问题。
脏读 | 不可重复读 | 虚读 | |
---|---|---|---|
READ UNCOMMIT 读未提交 | 有 | 有 | 有 |
READ COMMITTED 读已提交 | 无 | 有 | 有 |
REPEATABLE READ 可重复读 (MySQL 默认) | 无 | 无 | 有 |
SERIALIZABLE 串行化 | 无 | 无 | 无 |
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
超时时间 timeout
设置事务需要在一定时间内进行提交,超时则回滚。
默认值为-1,单位为秒。
@Transactional(timeout = 5)
readOnly 是否只读
读:查询操作
写:添加修改删除操作
默认值为 false,可读写
设置为 true,只能查询
rollbackFor 回滚
设置出现哪些异常需要回滚
noRollbackFor 是否只读
设置出现哪些异常不需要回滚
<bean
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
id="dataSourceTransactionManager"
>
<property name="dataSource" ref="dataSource">property>
bean>
<tx:advice id="txadvice">
<tx:attributes>
<tx:method name="transfer*" propagation="REQUIRES_NEW" />
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut
id="px"
expression="execution(* com.pyd.jdbctemplate.serivce.UserService.*(..))"
/>
<aop:advisor advice-ref="txadvice" pointcut-ref="px">aop:advisor>
aop:config>
@Configuration
@ComponentScan(basePackages = {"com.pyd.jdbctemplate"})
@EnableTransactionManagement // 开启事务
public class TxConfig {
// 创建数据库的连接池
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUsername("root");
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/dbtest");
druidDataSource.setPassword("");
druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
return druidDataSource;
}
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
// 注入datasource
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
常规升级:
基于 Java8 兼容 Java9
支持响应式编程,需要使用框架
自带日志封装
(1) Spring5 已经移除 Log4jConfigListener,官方建议使用 Log4j2
(2) Spring5 框架整合 Log4j2
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-apiartifactId>
<version>2.11.2version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>2.11.2version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.30version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-slf4j-implartifactId>
<version>2.11.2version>
dependency>
<configuration status="DEBUG">
<appenders>
<console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"
/>
console>
appenders>
<loggers>
<root level="info">
<appender-ref ref="Console" />
root>
loggers>
configuration>
public class Log {
private static final Logger log = LoggerFactory.getLogger(Log.class);
public static void main(String[] args) {
log.info("hello log4j");
log.warn("hello log4j");
}
}
Nullable:
GenericApplicationContext context = new GenericApplicationContext();
// 调用context对象进行注册,先清空
context.refresh();
context.registerBean(User.class, () -> new User());
context.registerBean("user1", User.class, () -> new User());
// 获取对象 全路径
User user = (User) context.getBean("com.pyd.User");
// 获取对象:指定名称
User user1 = (User) context.getBean("user1");
@RunWith(SpringJUnit4ClassRunner.class)
//单元测试框架
@ContextConfiguration("classpath:bean1.xml")
//加载配置文件
public class JTest4 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
}
}
需要引入 JUnit5 的 Jar 包
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:bean1.xml")
public class JTest5 {
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
}
}
@SpringJUnitConfig(locations = "classpath:bean1.xml")
public class JTest5{
@Autowired
private UserService userService;
@Test
public void test1() {
userService.accountMoney();
}
}
是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,Webflux 使用当前一种比较流程响应式编程出现的框架。
使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,WebFlux 是一种异步非阻塞的框架,异步非阻塞的框架在 Servlet 3.1 以后才支持,核心是基于 Reactor 的相关 API 实现的。