Spring

目录

目录

前言

一、spring是什么?

1.1 概念

1.2 spring下载

二、Spring框架的构成

三、Spring的使用

3.1 Maven项目中pox.xml中导入spring依赖

3.2 创建spring核心配置文件

四、Spring创建对象 和使用对象调用对象内的方法

4.1底层代码逻辑:

4.2 spring创建对象及使用对象的方式

4.3 spring三种给对象属性赋值的方式

4.3.1 set/get注入

4.3.2 构造器注入

4.3.3 自动注入(@Autowired注解)

4.4 bean的作用域

五、控制反转IOC(Inversion of Control)

5.1 项目中高耦合的问题

5.2 解决方案

六、Spring常用注解

七、 代理设计模式

7.1 静态代理设计模式

7.2 动态设计模式

八、AOP(Aspect Oriented Programming )面向切面编程

8.1概念

8.2 AOP常见术语

8.3 作用

8.4 AOP的使用

8.4.1 引入AOP相关依赖

8.4.2 spring-context.xml引入AOP命名空间

8.4.3 开发流程

九、spring的事务管理

9.1 声明式事务

9.1.1 xml文件配置

9.1.2 注解方式

9.2 编程式事务

9.2.1 execute方法

9.2.2 executeWithoutResult方法

9.3 事务的属性

9.3.1 隔离级别

9.3.2 传播行为

9.3.3 读写性

9.3.4 事务超时

9.3.5 事务回滚




前言

引用spring框架的目的:

1.解决软件开发中代码的高耦合现象

2.简化代码

3.提高代码的可移植性


一、spring是什么?

1.1 概念

  • Spring是一个项目管理框架,同时也是一套Java EE解决方案。

  • Spring是众多优秀设计模式的组合(工厂、单例、代理、适配器、包装器、观察者、模板、策略)。

  • Spring并未替代现有框架产品,而是将众多框架进行有机整合,简化企业级开发,俗称"胶水框架"。

1.2 spring下载

官方网站:Spring | Home

下载地址:JFrog

二、Spring框架的构成

Spring架构由诸多模块组成,可分类为

三、Spring的使用

3.1 Maven项目中pox.xml中导入spring依赖

<dependencies>
        <!-- Spring常用依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
    </dependencies>

3.2 创建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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   
</beans>

四、Spring创建对象 和使用对象调用对象内的方法

spring创建对象的工作原理(反射)-->通过反射获取类对象-->通过类对象创建对象

4.1底层代码逻辑:

userDAO=com.hrp.dao.UserDAOImpl
userService=com.hrp.service.UserServiceImpl

自定义工厂类

public class MyFactory {
    private Properties properties = new Properties();
    public MyFactory(){}
    public MyFactory(String config) throws IOException {
        // 加载配置文件
        properties.load(MyFactory.class.getResourceAsStream(config));
    }
    // 获取对象
    public Object getBean(String beanName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        // 获得类路径
        String classPath = properties.getProperty(beanName);
        if(classPath!=null){
            Class claz = null;
            // 反射:加载类对象
            claz = Class.forName(classPath);
            // 反射:获得对象
            return claz.newInstance();
        }
        return null;
    }
}

4.2 spring创建对象及使用对象的方式

创建实体类:

public class MyBeanClass {
    private Integer id;
    private String name;

    public void say(){
        System.out.println("hello");
    }
}

将实体类注册到spring容器(工厂)中:

<!-- 配置实例(id:“唯一标识”  class="需要被创建的目标对象全限定名") -->
<bean id="myBean" class="com.hrp.bean.MyBeanClass" />

调用Spring工厂API(ApplicationContext接口 ):

public class TestFactory{
    /**
     * 程序中的对象都交由Spring的ApplicationContext工厂进行创建。
     */
    public static void main(String[] args){
        //1. 读取配置文件中所需创建的bean对象,并获得工厂对象
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
        //2. 通过id获取bean对象
		MyBeanClass myBean= (MyBeanClass) ctx.getBean("myBean");
        //3. 使用对象  调用say()方法
		myBean.say();
    }
}

4.3 spring三种给对象属性赋值的方式

实体类:

public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private Date birthday;
    private int[]arr;
    private List<String>list;
    private Set<String>set;
    private Map<String,String>map;
    private Properties properties;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public int[] getArr() {
        return arr;
    }

    public void setArr(int[] arr) {
        this.arr = arr;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public Set<String> getSet() {
        return set;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                ", arr=" + Arrays.toString(arr) +
                ", list=" + list +
                ", set=" + set +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
}

4.3.1 set/get注入

        在<property></property>标签中给对象属性赋值name指的是对象的属性名value则是属性对应的属性值;引用数据类型则需要用ref=引用对象的id

基本类型+字符串类型+日期类型

<bean id="date" class="java.util.Date"/>

    <bean id="person1" class="com.hrp.demotest.Person">
        <property name="id" value="1"/>
        <property name="name" value="张三"/>
        <property name="age" value="22"/>
        <property name="birthday" ref="date"/>
    </bean>

容器类型(list、set、map、array、properties等)

 <property name="arr">
            <array>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
                <value>list3</value>
            </list>
        </property>
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
                <value>set3</value>
            </set>
        </property>
        <property name="map">
            <map>
                <entry key="map1" value="map1"></entry>
                <entry key="map2" value="map2"></entry>
                <entry key="map3" value="map3"></entry>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="prop1">prop1</prop>
                <prop key="prop2">prop2</prop>
                <prop key="prop3">prop3</prop>
            </props>
        </property>

自建类型

<!--次要bean,被作为属性-->
<bean id="addr" class="com.hrp.bean.Address">
    <property name="city" value="上海" />
    <property name="cityCode" value="100001" />
</bean>

<!--主要bean,操作的主体-->
<bean id="user" class="com.hrp.bean.User">
    <property name="address" ref="addr" /><!--address属性引用addr对象-->
</bean>

4.3.2 构造器注入

        实体类:

public class Student {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
  
    //构造器
  	public Student(Integer id , String name , String sex , Integer age){
      	this.id = id;
    	this.name = name;
  	    this.sex = sex;
	    this.age = age;
    }
}

        构造器注入:

 <!--构造注入-->
<bean id="u3" class="com.hrp.bean.Student">
    <constructor-arg name="id" value="1234" /> <!-- 除标签名称有变化,其他均和Set注入一致 -->
    <constructor-arg name="name" value="tom" />
    <constructor-arg name="age" value="20" />
    <constructor-arg name="sex" value="male" />
</bean>

4.3.3 自动注入(@Autowired注解)

不用在配置中 指定为哪个属性赋值,及赋什么值.

由spring自动根据某个 "原则" ,在工厂中查找一个bean,为属性注入属性值

4.4 bean的作用域

     

singleton单例、容器初始化时创建
prototype多例、使用时创建
request每一次HTTP请求都产生一个新的bean,仅在当前HTTP request内生效
session每一次HTTP请求都产生一个新的bean,仅在当前HTTP session内生效
global session仅在基于portlet的web应用中才有意义

五、控制反转IOC(Inversion of Control)

        反转了依赖关系的满足方式,由之前的自己创建依赖对象,变为由工厂推送。(变主动为被动,即反转)

        解决了具有依赖关系的组件之间的强耦合,使得项目形态更加稳健

5.1 项目中高耦合的问题

public class UserDAOImpl implements UserDAO{....}

public class UserServiceImpl implements UserService {
    // !!!强耦合了UserDAOImpl!!!,使得UserServiceImpl变得不稳健
    private UserDAO userDAO= new UserDAOImpl();
    @Override
    public User queryUser() {
        return userDAO.queryUser();
    }
    ....
}

5.2 解决方案

// 不引用任何一个具体的组件(实现类),在需要其他组件的位置预留存取值入口(set/get)
public class UserServiceImpl implements UserService {
    // 不再耦合任何DAO实现!!!,消除不稳健因素
    private UserDao userDao;


    // 为userDAO定义set/get,允许userDAO属性接收spring赋值
    //Getters And Setters
    public UserDao getUserDao() {
        return userDao;
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }


    @Override
    public void hello() {
        userDao.say();
    }
}
<bean id="userDAO" class="com.hrp.dao.impl.UserDaoImpl"></bean>
<!-- UserServiceImpl组件 -->
<bean id="userService" class="com.hrp.dao.impl.UserServiceImpl">
    <!-- 由spring为userDAO属性赋值,值为id="userDAO"的bean -->
    <property name="userDAO" ref="userDAO"/>
</bean>

六、Spring常用注解

@Repository常用于dao层的类中
@Service常用于service层的类中
@Controller常用于Controller层的类中
@Autowired自动注入  常写于属性上方
@Autowired+Qualifier (bean类名称)等同于@Autowired

        @Autowired  + byName   根据属性名称寻找类型 属性名与id相同

        @Autowired  + byType     根据类型  相同类型>1则报错

PS:使用注解需要在xml中配置

<context:component-scan base-package="扫的包”></context;component-scan>

如:<context:component-scan base-package="com.hrp”></context;component-scan>会扫描com包下hrp目录的所有类中的注解

七、 代理设计模式

        将核心功能与辅助功能(事务、日志、性能监控代码)分离,达到核心业务功能更纯粹、辅助业务功能可复用。

7.1 静态代理设计模式

        通过代理类的对象,为原始类的对象(目标类的对象)添加辅助功能,更容易更换代理实现类、利于维护。

        代理类 = 实现原始类相同接口 + 添加辅助功能 + 调用原始类的业务方法。

静态代理的问题

代理类数量过多,不利于项目的管理。

多个代理类的辅助功能代码冗余,修改时,维护性差。

7.2 动态设计模式

        动态创建代理类的对象,为原始类的对象添加辅助功能。

                

① JDK动态代理实现(基于接口 )--》有接口的情况

@Test
    public void jdkProxyTest() {
        //目标类
        UserService userService = new UserServiceImpl();
        //额外功能
        InvocationHandler invocationHandler = new InvocationHandler() {
            //设置回调函数(额外功能代码)
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("前置通知");
                method.invoke(userService, objects);
                return null;
            }
        };
        //创建动态代理类
        UserService userService1 =(UserService) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
        //调用方法
        userService1.add();
    }

②CGlib动态代理实现(基于继承)--》无接口的情况

 @Test
    public void cglibProxyTest() {
        //目标类
        UserService userService = new UserServiceImpl();
        Enhancer enhancer = new Enhancer();//字节码增强对象
        enhancer.setSuperclass(userService.getClass());//设置被代理类的类对象
        enhancer.setCallback(new InvocationHandler() {//设置代理类重写的方法
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("前置通知");
                method.invoke(userService, objects);
                return null;
            }
        });
        UserService userService1 = (UserService) enhancer.create();
        userService1.add();
    }

八、AOP(Aspect Oriented Programming )面向切面编程

8.1概念

        AOP(Aspect Oriented Programming),即面向切面编程,利用一种称为"横切"的技术,剖开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说在不修改原代码的情况下用无代码侵入的方式增强原始类的功能  比如 验证功能、日志功能、事务的提交和关闭等都可以通过AOP技术实现

8.2 AOP常见术语

  • 连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。

  • 切入点(Pointcut):被Spring切入连接点。

  • 通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知等。

  • 目标对象(Target):代理的目标对象

  • 引介(Introduction):一种特殊的增强,可在运行期为类动态添加Field和Method。

  • 织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程。

  • 代理(Proxy):被AOP织入通知后,产生的结果类。

  • 切面(Aspect):由切点和通知组成,将横切逻辑织入切面所指定的连接点中。

8.3 作用

      Spring的AOP编程即是通过动态代理类原始类的方法添加辅助功能

8.4 AOP的使用

8.4.1 引入AOP相关依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.22</version>
</dependency>

8.4.2 spring-context.xml引入AOP命名空间

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       ">
</beans>

8.4.3 开发流程

①定义原始类

public interface UserService {
    void update();
    void add();
    void getAll();
    void delete();
    void getOne();
}


//实现接口
public class UserServiceImpl implements UserService{
    @Override
    public void update() {
        System.out.println("执行修改");
    }

    @Override
    public void add() {
        System.out.println("执行新增");
    }

    @Override
    public void getAll() {

        System.out.println("执行查询所有");
    }

    @Override
    public void delete() {
        System.out.println("执行删除");
    }

    @Override
    public void getOne() {
        System.out.println("执行查询单个");
        int i =2/0;
    }
}

②定义通知类(添加辅助功能)下图为前置通知案例

public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(new Date());
    }
}

前置通知:MethodBeforeAdvice 在目标方法执行之前执行执行的通知

后置通知:AfterAdvice   在目标方成功执行之后执行的通知。

后置通知:AfterReturningAdvice 返回后通知

异常通知:ThrowsAdvice 在目标方法抛出异常时执行的通知。

环绕通知:MethodInterceptor 目标方法执行之前和之后都可以执行额外代码的通知

③配置spring-Context.xml

定义bean标签

<!--配置原始类对象-->
    <bean id="userServiceImpl" class="com.hrp.service.UserServiceImpl"/>
    <!--配置通知-->
    <bean id="myAdvice" class="com.hrp.advice.BeforeAdvice"/>
    <!-- 配置切点-->
    <aop:config>
        <aop:pointcut id="myPointcut" expression="execution(* com.hrp.service.UserService.update())"/>
    <!--配置切面
    advice-ref 配置通知
    pointcut-ref 配置切点
    -->
    <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointcut"></aop:advisor>
    </aop:config>

九、spring的事务管理

事务的特性(ACID):原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Duration)。

9.1 声明式事务

9.1.1 xml文件配置

创建实体类:

Person实体类:

public class Person {
    private Integer id;
    private String name;//账户
    private Integer balance;//余额

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getBalance() {
        return balance;
    }

    public void setBalance(Integer balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", balance=" + balance +
                '}';
    }
}

Book实体类:

public class Book {
    private String isbn;//书的编号
    private String name;//书名
    private String author;//作者
    private Integer price;//书价
    private Integer stock;//库存

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Book{" +
                "isbn='" + isbn + '\'' +
                ", name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }
}

Person类的dao接口及实现类

public interface PersonDao {
    Person selectByAccount(String name);//通过账户查询
    int updateBalance(String account,Integer bookPrice);//更新余额
}



@Repository
public class PersonDaoImpl implements PersonDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public Person selectByAccount(String name) {

        return jdbcTemplate.queryForObject("select * from person where name = ?", new RowMapper<Person>() {

            @Override
            public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
                    Person person = new Person();
                    person.setId(rs.getInt(1));
                    person.setName(rs.getString(2));
                    person.setBalance(rs.getInt(3));
                return person;
            }
        }, name);
    }

    @Override
    public int updateBalance(String name, Integer bookPrice) {
        return jdbcTemplate.update("update person set balance=balance-? where name =?",bookPrice,name);
    }
}

        Book类的dao接口及实现类:

public interface BookDao {
    Book selectByIsbn(String isbn);//根据isbn查询book
    int updateStock(String isbn);//更新库存
}


@Repository
public class BookDaoImpl implements BookDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public Book selectByIsbn(String isbn) {
        Book book = jdbcTemplate.queryForObject("select * from book where isbn=?", new RowMapper<Book>() {
            @Override
            public Book mapRow(ResultSet rs, int rowNum) throws SQLException {
                Book bk = new Book();
                bk.setIsbn(rs.getString(1));
                bk.setName(rs.getString(2));
                bk.setAuthor(rs.getString(3));
                bk.setPrice(rs.getInt(4));
                bk.setStock(rs.getInt(5));


                return bk;
            }
        }, isbn);
        return book;
    }

    @Override
    public int updateStock(String isbn) {

        return jdbcTemplate.update("update book set stock=stock-1 where isbn=?",isbn);
    }
}

Book类的业务接口及实现类

public interface BookService {

    void bookDeal(String name,String ibsn);//书的交易
}


@Service
public class BookServiceImpl implements BookService{
    @Autowired
    private BookDao bookDao;
    @Autowired
    private PersonDao personDao;
    @Override
    public void bookDeal(String name, String ibsn) {

        Book book = bookDao.selectByIsbn(ibsn);
        Person person = personDao.selectByAccount(name);
        System.out.println("交易前book:"+book);
        System.out.println("交易前person:"+person);
        if (person.getBalance()>=book.getPrice()){//如果用户的账户余额大于书的价格 则账户余额-书价
            personDao.updateBalance(name,book.getPrice());
        }else {
            throw new RuntimeException("嗨呀,余额不足");
        }


        if (book.getStock()>=1){//如果书的库存大于1 就库存-1
                bookDao.updateStock(ibsn);
        }else {
            throw new RuntimeException("哦吼,库存不足");
        }
        Book book1 = bookDao.selectByIsbn(ibsn);
        Person person1 = personDao.selectByAccount(name);
        System.out.println("交易后book:"+book1);
        System.out.println("交易后person:"+person1);

    }
}
<?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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--    配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///studentsys"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    <!--    配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>


    <!--事务传播行为
        int PROPAGATION_REQUIRED = 0; //支持当前事务,如果不存在,就新建一个
        int PROPAGATION_SUPPORTS = 1; //支持当前事务,如果不存在,就不使用事务
        int PROPAGATION_MANDATORY = 2; //支持当前事务,如果不存在,就抛出异常
        int PROPAGATION_REQUIRES_NEW = 3;//如果有事务存在,挂起当前事务,创建一个新的事物
        int PROPAGATION_NOT_SUPPORTED = 4;//以非事务方式运行,如果有事务存在,挂起当前事务
        int PROPAGATION_NEVER = 5;//以非事务方式运行,如果有事务存在,就抛出异常
        int PROPAGATION_NESTED = 6;//如果有事务存在,则嵌套事务执行
    -->
    <!--配置事务的通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--配置事务属性-->
        <tx:attributes>
            <tx:method name="bookDeal"/>
        </tx:attributes>
    </tx:advice>
<aop:config>
    <aop:pointcut id="txPointcut" expression="execution(* com.hrp.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
    <!--配置jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    配置注解扫描-->
    <context:component-scan base-package="com.hrp"/>
</beans>

9.1.2 注解方式

????

9.2 编程式事务

9.2.1 execute方法

TransactionTemplate是spring提供出来的能够操作spring中的事务的操作。

使用TransactionTemplate需要配置一个PlatformTransactionManager,但是不需要配置事务定义。因为在TransactionTemplate中,spring已经帮我们配置好了。

直接看下最为核心的方法:execute

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
  Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

  if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
    return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
  }
  else {
    // 获取得到事务状态信息,然后执行对应的方法
    TransactionStatus status = this.transactionManager.getTransaction(this);
    T result;
    try {
      result = action.doInTransaction(status);
    }
      // 执行失败逻辑
    catch (RuntimeException | Error ex) {
      // Transactional code threw application exception -> rollback
      rollbackOnException(status, ex);
      throw ex;
    }
    catch (Throwable ex) {
      // Transactional code threw unexpected exception -> rollback
      rollbackOnException(status, ex);
      throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
    }
      // 执行成功逻辑
    this.transactionManager.commit(status);
    return result;
  }
}

9.2.2 executeWithoutResult方法

和execute的区别的地方就在于:看返回值是否有对应的结果。如果有返回值,那么就直接使用execute方法;如果没有返回值,就直接使用executeWithoutResult方法即可。那么来看下这里的原理:

	default void executeWithoutResult(Consumer<TransactionStatus> action) throws TransactionException {
		execute(status -> {
			action.accept(status);
			return null;
		});
	}

9.3 事务的属性

9.3.1 隔离级别

名称描述
default(默认值)(采用数据库的默认的设置) (建议)
read-uncommited读未提交 (会产生脏读/不可重复读/幻读的风险)
read-commited读提交 (会产生不可重复读/幻读的风险)
repeatable-read可重复读 (会产生幻读)(MySQL数据库默认的隔离级别)
serialized-read序列化读(最安全,但效率最低)

脏读:读到了其它事务未提交的数据,数据可能回滚,读到了没有存储在数据库中的数据

不可重复读:在一个事务内,多次读取同一条数据,结果不同 (和幻读的区别是  幻读数据会消失  不可重复读只是内容改变)

9.3.2 传播行为

int PROPAGATION_REQUIRED = 0; //支持当前事务,如果不存在,就新建一个
int PROPAGATION_SUPPORTS = 1; //支持当前事务,如果不存在,就不使用事务
int PROPAGATION_MANDATORY = 2; //支持当前事务,如果不存在,就抛出异常
int PROPAGATION_REQUIRES_NEW = 3;//如果有事务存在,挂起当前事务,创建一个新的事物
int PROPAGATION_NOT_SUPPORTED = 4;//以非事务方式运行,如果有事务存在,挂起当前事务
int PROPAGATION_NEVER = 5;//以非事务方式运行,如果有事务存在,就抛出异常
int PROPAGATION_NESTED = 6;//如果有事务存在,则嵌套事务执行

9.3.3 读写性

readonly
true只读,可提高查询效率。(适合查询)
flase可读可写。 (默认值)(适合增删改)

9.3.4 事务超时

timeout  事务超时时间 当前事务所需操作的数据被其他事务占用,则等待。
100自定义等待时间100(秒)。
-1由数据库指定等待时间,默认值。(建议)

9.3.5 事务回滚

rollback-for  事务回滚
rollback-for如果事务中抛出 RuntimeException,则自动回滚
no-rollback-for如果事务中抛出异常,事务不回滚

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值