Spring学习?这一篇文章就够,史上最全!

文章目录

  • 前言
  • 一、IOC概述及底层原理
    • 1.概述和原理
  • 二、思路分析
  • 三、IOC操作bean管理(基于xml,使用的是IDEA2022.3.3,maven仓库)
    • 1.xml实现bean管理
      • (1)创建对象
      • (2)注入属性
      • (3)p名称空间注入
      • (4)其他注入
        • 1.注入的属性值是null或者有符号,如下:
        • 2.注入外部bean,如下:
        • 3.内部bean注入
        • 4.级联赋值
        • 5.注入集合
      • (5)FactoryBean(工厂bean)
    • 2.bean的作用域
    • 3.bean的生命周期
    • 4.xml自动配置属性值
    • 5.外部属性文件操作bean
  • 四、注解实现bean管理
    • 1.基于注解创建对象
    • 2.组件扫描细节
    • 3.基于注解进行属性注入
  • 五、完全注解开发
  • 六、AOP概述和原理
    • 1.概述和原理
    • 2.JDK动态代理实例
  • 七、基于AspectJ实现的AOP操作
    • 1.什么是AspectJ
    • 2.AOP相关术语
    • 3.切点表达式
    • 3.基于注解方式实现
      • (1)实例:
      • (2)切入点提取
      • (3)设置增强类优先级
      • (4)完全注解开发
    • 4.基于xml配置文件实现(了解)
  • 八、JdbcTemplate
    • 1.相关依赖(AOP、IOC、JdbcTemplate都有)
    • 2.代码实战
      • (1)方法讲解
      • (2)代码实例
  • 九、事务及其参数含义
    • 1.事务的四个特性
    • 2.事务的传播行为(propagation)
    • 3.事务隔离性
    • 4.事务的隔离级别(ioslation)
    • 5.timeout(超时)
    • 6.readOnly(是否只读)
    • 7.rollbackFor(回滚)
    • 8.noRollbackFor(不回滚)
  • 十、事务管理
    • 1.事务管理的两种形式
    • 2.注解实现声明式事务管理
    • 3.xml实现声明式事务管理
    • 4.完全注解开发
  • 总结


前言

Spring框架:IOC、AOP、JdbcTemplate、事务管理,带你一篇速通。


一、IOC概述及底层原理

1.概述和原理

  • IOC是控制反转的意思。使用对象时候由主动new对象转换成由外部提供对象,此过程中对象的创建权由程序转移到外部,这种思想叫做控制反转。即把对象创建和对象的调用过程交给spring进行管理。
  • 目的:降低耦合度。
  • 底层原理:xml配置,反射,工厂模式。
  • Spring提供IOC容器两种实现方式(两个接口)
    (1)BeanFactory:Spring内部使用的接口,不提倡开发人员使用。特点:加载配置文件时不会创建对象,获取对象时才会创建对象。
    (2)ApplicationContext:BeanFactory的子接口,提供了更多更强大的功能,一般由开发人员使用。特点:加载配置文件时会把配置文件里的对象进行创建。
    (3)核心:Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的外部
    IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean。
  • ApplicationContext两个常用的实现类:
    (1)FileSystemXmlApplicationContext:绝对路径,从盘符开始算起
    (2)ClassPathXmlApplicationContext:相对路径,从项目的src开始算起
    在这里插入图片描述
  • IOC实现:依赖注入,即在容器中建立bean与bean之间的依赖关系的整个过程。

二、思路分析

  • IOC管理什么(bean对象)
  • 如何告知IOC去管理bean对象(通过配置文件)
  • 被管理的对象交给IOC容器,如何获取IOC容器?(接口)
  • IOC容器得到后,如何获取bean?(通过ApplicationContext接口的两个实现类的getBean方法获取bean实例创建对象)

三、IOC操作bean管理(基于xml,使用的是IDEA2022.3.3,maven仓库)

首先告诉大家本篇文章的所有使用的spring依赖版本:

    <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>6.0.9</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.9</version></dependency></dependencies>

1.xml实现bean管理

(1)创建对象

项目的resource资源文件夹创建spring的配置文件,然后添加如下代码:

<bean id="book" class="com.dragon.spring5.Book"></bean>
  • id:创建对象的名称
  • class:Book类的路径
  • 创建对象时默认是执行无参构造函数
    在这里插入图片描述

(2)注入属性

创建对象后,对象内的属性还没有赋值等等,讲诉三种注入属性得到方式:

  • 第一种:set方法注入
    这种方法需要类的属性有对应的set方法,如下:
public class Book {private String bname;private String bauthor;public void setBname(String bname) {this.bname = bname;}public void setBauthor(String bauthor) {this.bauthor = bauthor;}public void testbook(){System.out.println(bname+":"+bauthor);}
}

然后在spring配置文件中通过property标签进行属性注入,如下:

<bean id="book" class="com.dragon.spring5.Book"><property name="bname" value="易筋经"></property><property name="bauthor" value="达摩老祖"></property>
</bean>

然后测试:

	<!--加载spring配置文件创建对象-->ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");<!--反射-->Book book=context.getBean("book", Book.class);System.out.println(book);book.testbook();

在这里插入图片描述

  • 第二种:有参构造方法注入
    提供有参构造方法:
public class Book {private String bname;private String bauthor;public Book(String bname, String bauthor) {this.bname = bname;this.bauthor = bauthor;}public void testbook(){System.out.println(bname+":"+bauthor);}
}

然后在spring配置文件中,如下:

<bean id="book" class="com.dragon.spring5.Book"><constructor-arg name="bname" value="易筋经"></constructor-arg><constructor-arg name="bauthor" value="达摩老祖"></constructor-arg>
</bean>

(3)p名称空间注入

set方法、测试的代码跟上诉一样,不再赘诉。
在spring配置文件中添加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"<!--添加p名称空间-->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"><bean id="book" class="com.dragon.spring5.Book" p:bname="九阴神功" p:bauthor="无名氏"></bean></beans>

在这里插入图片描述

(4)其他注入

1.注入的属性值是null或者有符号,如下:
<bean id="book" class="com.dragon.spring5.Book"><property name="bauthor"><null/></property><property name="bname"><value><![CDATA[<<读者>>]]></value></property></bean>
  • 有符号:用<![CDATA[带符号的属性值(包括符号)]]>
  • 空值:< null />

在这里插入图片描述

2.注入外部bean,如下:

spring配置文件:

  • ref:引用外部bean的id值
    <bean id="userService" class="com.dragon.spring5.service.UserService"><property name="userDao" ref="userDaoImpl"></property></bean><bean id="userDaoImpl" class="com.dragon.spring5.dao.UserDaoImpl"></bean>

UserService、UserDao、UserDaoImpl、测试类代码:

package com.dragon.spring5.dao;public interface UserDao {public void update();
}
=============================================================
package com.dragon.spring5.dao;public class UserDaoImpl implements UserDao{@Overridepublic void update() {System.out.println("dao update.......");}
}
=========================================================
package com.dragon.spring5.service;import com.dragon.spring5.dao.UserDao;public class UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void add(){System.out.println("service add........");userDao.update();}
}
======================================================
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
UserService userService=context.getBean("userService", UserService.class);
userService.add();

在这里插入图片描述

3.内部bean注入

不通过ref属性,而是通过嵌套一个bean标签实现
spring配置文件:

        <bean id="emp" class="com.dragon.spring5.bean.Emp"><property name="enanme" value="lucy"></property><property name="gender" value="女"></property><property name="dept"><bean id="dept" class="com.dragon.spring5.bean.Dept"><property name="dname" value="保安部门"></property></bean></property></bean>

Emp、Dept、测试类代码:

package com.dragon.spring5.bean;public class Emp {private String enanme;private String gender;private Dept dept;public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept = dept;}public void setEnanme(String enanme) {this.enanme = enanme;}public void setGender(String gender) {this.gender = gender;}public void add(){System.out.println(enanme+"::"+gender+"::"+dept);}
}
===================================================================
package com.dragon.spring5.bean;public class Dept {private String dname;public void setDname(String dname) {this.dname = dname;}@Overridepublic String toString() {return "Dept{" +"dname='" + dname + '\'' +'}';}
}
==========================================================================
ApplicationContext context1=new ClassPathXmlApplicationContext("bean2.xml");Emp emp=context1.getBean("emp", Emp.class);emp.add();

在这里插入图片描述

4.级联赋值

写法一:也就是上面所说的外部bean,通过ref属性来获取外部bean
写法二:
emp类中有ename和dept两个属性,其中dept有dname属性,写法二需要emp提供dept属性的get方法。

                <bean id="emp" class="com.dragon.spring5.bean.Emp"><property name="enanme" value="john"></property><property name="gender" value="男"></property><!--写法一--><property name="dept" ref="dept"></property><!--写法二--><property name="dept.dname" value="技术部"></property></bean><bean id="dept" class="com.dragon.spring5.bean.Dept"><property name="dname" value="财务部"></property></bean>
5.注入集合

stu类:

package com.dragon.spring5.collectiontype;import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;public class Stu {private String[] courses;private List<String> list;private Map<String,String> maps;private Set<String> sets;private List<Course> courselist;public void setCourselist(List<Course> courselist) {this.courselist = courselist;}public void setSets(Set<String> sets) {this.sets = sets;}public void setCourses(String[] courses) {this.courses = courses;}public void setList(List<String> list) {this.list = list;}public void setMaps(Map<String, String> maps) {this.maps = maps;}public void test(){System.out.println(Arrays.toString(courses));System.out.println(list);System.out.println(maps);System.out.println(sets);System.out.println(courselist);}
}

Course类:

package com.dragon.spring5.collectiontype;public class Course {private String cname;public void setCname(String cname) {this.cname = cname;}@Overridepublic String toString() {return "Course{" +"cname='" + cname + '\'' +'}';}
}

spring配置文件:

<bean id="stu" class="com.dragon.spring5.collectiontype.Stu"><property name="courses"><array><value>java课程</value><value>数据库课程</value></array></property><property name="list"><list><value>张三</value><value>小三</value></list></property><property name="maps"><map><entry key="JAAVA" value="java"></entry><entry key="PHP" value="php"></entry></map></property><property name="sets"><set><value>MySQL</value><value>Redis</value></set></property><!--外部bean注入--><property name="courselist"><list><ref bean="course1"></ref><ref bean="course2"></ref></list></property>
</bean>
<bean id="course2" class="com.dragon.spring5.collectiontype.Course"><property name="cname" value="MyBatis框架"></property>
</bean>

测试:

		ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");Stu stu=context.getBean("stu", Stu.class);stu.test();

在这里插入图片描述
集合提取出来注入:
用util标签(注意util标签怎么引入):
Book类:

package com.dragon.spring5.collectiontype;import java.util.List;public class Book {private List<String> list;public void setList(List<String> list) {this.list = list;}public void test(){System.out.println(list);}
}
<?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"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><util:list id="booklist"><value>易筋经</value><value>九阳神功</value><value>九阴真经</value></util:list><bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype"><property name="list" ref="booklist"></property></bean>
</beans>

(5)FactoryBean(工厂bean)

普通bean在配置文件中定义的bean类型就是返回类型。而工厂bean在配置文件定义的bean类型可以和返回类型不一样。
下面的MyBean类中实现FactoryBean接口,重写getObject,getObjectType方法。
这里把getObject重写成返回Course对象的方法。

package com.dragon.spring5.factorybean;import com.dragon.spring5.collectiontype.Course;
import org.springframework.beans.factory.FactoryBean;public class MyBean implements FactoryBean<Course> {@Overridepublic Course getObject() throws Exception {Course course=new Course();course.setCname("abc");return course;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();}
}

spring配置文件:

<bean id="mybean" class="com.dragon.spring5.factorybean.MyBean"></bean>

测试:
注意这里实例化对象不是MyBean类型,是上面getObject方法返回的对象类型。

		ApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");Course course=context.getBean("mybean", Course.class);System.out.println(course);

在这里插入图片描述

2.bean的作用域

  • 在Spring中,默认情况下bean创建的是单实例对象:
 		ApplicationContext context1=new ClassPathXmlApplicationContext("bean4.xml");Book book1=context1.getBean("book", Book.class);Book book2=context1.getBean("book", Book.class);

在这里插入图片描述
可以看出地址一样

  • bean有个属性是scope,可以通过设置成singleton或prototype来决定其是单实例还是多实例(1)singleton:默认值,表示单实例对象。加载配置文件时就会创建单实例对象。
    (2)prototype:表示多实例对象。不是在加载配置文件时创建对象,在调用getBean方法时创建多实例对象。
<bean id="book" class="com.dragon.spring5.collectiontype.Book" scope="prototype"><property name="list" ref="booklist"></property>
</bean>

在这里插入图片描述

  • scope的值还可以是request、session(大家应该知道这两个值的作用域吧)

3.bean的生命周期

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization

(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)

(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization

(6)bean 可以使用了(对象获取到了)

(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
下面提供大家测试需要用的类,方便大家理解:
Orders类:

package com.dragon.spring5.bean;public class Orders {private String oname;public Orders() {System.out.println("第一步 执行无参数构造创建bean实例");}public void setOname(String oname) {this.oname = oname;System.out.println("第二步 调用set方法设置属性值");}public void initMethod(){System.out.println("第三步 执行初始化方法");}public void destoryMethod(){System.out.println("第五步 bean销毁的方法");}
}

后置处理器:

package com.dragon.spring5.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之前执行的方法");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("在初始化之后执行的方法");return bean;}
}

测试:

package com.dragon.spring5.testDemo;import com.dragon.spring5.bean.Orders;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class test3 {public static void main(String[] args) {ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean6.xml");Orders orders=context.getBean("orders", Orders.class);System.out.println("第四步 获取创建beam实例对象");System.out.println(orders);context.close();}
}

spring配置文件:

        </bean>
<!--        后置处理器--><bean id="myBeanPost" class="com.dragon.spring5.bean.MyBeanPost"></bean>

在这里插入图片描述

4.xml自动配置属性值

bean标签属性autowire两个常用值:
(1)byName:根据属性名称注入,注入值bean的id值和类属性名称一样
(2)byType:根据属性类型注入
spring配置文件:
(Emp类中有dept属性)

<bean id="emp" class="com.dragon.spring5.autowrite.Emp"><property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>

正常情况下属性值需要用property标签注入。
而用autowire,可以自动注入

        <bean id="emp" class="com.dragon.spring5.autowrite.Emp" autowire="byName"></bean><bean id="dept" class="com.dragon.spring5.autowrite.Dept"></bean>

5.外部属性文件操作bean

这里用连接数据库举例:
在resource文件夹内jdbc属性文件(jdbc.properties)

pro.driverClass=com.mysql.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/?(这个根据自己数据库配置)
pro.username=root
pro.password=root

spring配置文件(注意context配置,这里使用的< context:property-placeholder/ >标签引入属性文件,其中classpath就是配置属性文件的全称):

<?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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean>
</beans>

四、注解实现bean管理

1.基于注解创建对象

spring提供四种创建对象的注解(下面四个注解说的一般使用在哪层是约定俗成的,其实效果都一样,都可以混用):

  • @Component
  • @Service:一般用于业务逻辑或Service层
  • @Controller:一般用于web层
  • @ Repository:一般用于Dao层
    步骤:
    (1)引入依赖(开头已告知所有maven依赖库)
    (2)开启组件扫描:扫描base-package包下所有有注解的类并为其创建对象
<context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>

代表扫描com.dragon.spring5_1下的所有文件,找寻有注解的文件,然后创建实例。
(2)创建类并在类上创建对象注解

@Service(value = "userService")
public class UserService {public void add(){System.out.println("service add.......");}
}

测试:

        ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");UserService userService=context.getBean("userService",UserService.class);System.out.println(userService);userService.add();

在这里插入图片描述

2.组件扫描细节

还有两种用法:

        设置不扫描的注解<context:component-scan base-package="com.dragon.spring5_1"><context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/></context:component-scan>设置扫描的注解<context:component-scan base-package="com.dragon.spring5_1" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/></context:component-scan>

3.基于注解进行属性注入

  • @Autowired:根据属性类型自动装配
  • @Qualifier:根据属性名称自动装配,需要和@Autowired一起使用
    当遇到一个接口有很多实现类时,只通过@Autowire是无法完成自动装配的,所以需要再使用@Qualifier通过名称来锁定某个类
  • @Resource:可以根据类型注入,也可以根据名称注入(不常用)
  • @Value:注入属性值
    实例:
    UserDao、UserDaoImpl、UserService类:
package com.dragon.spring5_1.dao;import org.springframework.stereotype.Repository;public interface UserDao {public void add();
}
==================================================
package com.dragon.spring5_1.dao;import org.springframework.stereotype.Repository;@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{@Overridepublic void add() {System.out.println("dao add......");}
}
=========================================================
package com.dragon.spring5_1.service;import com.dragon.spring5_1.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service(value = "userService")
public class UserService {@Value(value = "abc")private String name;@Autowired@Qualifier(value ="userDaoImpl1")private UserDao userDao;public void add(){System.out.println("service add......."+name);userDao.add();}
}

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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.dragon.spring5_1"></context:component-scan>
</beans>

测试:

	ApplicationContext context=new ClassPathXmlApplicationContext("bean9.xml");UserService userService=context.getBean("userService",UserService.class);System.out.println(userService);userService.add();

在这里插入图片描述

五、完全注解开发

上面讲诉后,完全注解开发应该是最简洁的。来个实例看一看。
这时要引入配置类来代替spring配置文件,来实现组件扫描不用xml配置,进而实现完全注解开发。
配置类:

package com.dragon.spring5_1.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration//配置类
@ComponentScan(basePackages = {"com.dragon.spring5_1"})//配置扫描的文件
public class SpringConfig {}

测试(UserDao、UserDaoImpl、UserService还是上面基于注解属性注入例子的):

package com.dragon.spring5_1.testDemo;import com.dragon.spring5_1.config.SpringConfig;
import com.dragon.spring5_1.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class test2 {public static void main(String[] args) {//注意new的对象变了,变成了AnnotationConfigApplicationContextApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);UserService userService=context.getBean("userService", UserService.class);System.out.println(userService);	userService.add();}
}

六、AOP概述和原理

用的依赖(包括上篇文章讲诉的IOC依赖):

       <dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>6.0.9</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version><scope>runtime</scope></dependency><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><dependency><groupId>net.sourceforge.cglib</groupId><artifactId>com.springsource.net.sf.cglib</artifactId><version>2.1.3</version></dependency>

1.概述和原理

  • AOP:面向切面编程。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗来说就是在不修改代码的情况下添加新的功能。
  • 底层通过动态代理实现:
    (1)有接口情况:使用JDK动态代理,即创建接口实现类的代理对象。
    (2)无接口情况:使用CGLIB动态代理,即创建当前类子类的代理对象。

2.JDK动态代理实例

核心:

  • 通过 java.lang.reflect.Proxy类 的 newProxyInstance方法 创建代理类。
  • newProxyInstance方法
    在这里插入图片描述
    参数一:类加载器
    参数二:所增强方法所在的类,这个类实现的接口,支持多个接口
    参数三:实现InvocationHandle接口,重写invoke方法来添加新的功能
    模拟代理:
    UserDao、UserDaoImpl类:
package com.dragon.springaop;public interface UserDao {public int add(int a,int b);public String update(String id);
}
================================================
package com.dragon.springaop;public class UserDaoImpl implements UserDao{@Overridepublic int add(int a,int b) {System.out.println("add方法执行了...");return a+b;}@Overridepublic String update(String id) {System.out.println("update方法执行了...");return id;}
}

JDKProxy类(通过 java.lang.reflect.Proxy类 的 newProxyInstance方法创建代理类):

package com.dragon.springaop;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;public class JDKProxy {public static void main(String[] args) {Class[] interfaces={UserDao.class};//创建接口实现类代理对象UserDaoImpl userDao=new UserDaoImpl();UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDao)) ;int result=dao.add(1,2);System.out.println("result:"+result);}
}
class UserDaoProxy implements InvocationHandler{//创建的是谁的代理对象,把谁传递过来//有参构造传递private Object obj;public UserDaoProxy (Object obj){this.obj=obj;}//参数含义:代理对象、方法、参数@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法之前执行...."+ method.getName()+":传递参数...."+ Arrays.toString(args));Object res=method.invoke(obj,args);System.out.println("方法之后执行...."+obj);return res;}
}

在这里插入图片描述
其实JDK动态代理本质就是在原来要增强的方法前面或后面增加一些逻辑处理等,而不修改源代码。从上面运行结果看以看出,add方法执行结果是3,但是在执行add方法执行多一些语句输出,这些就是我们增加的逻辑处理部分。其中method.invoke()就是模拟的原add方法执行,而前后的输出语句是模拟的增强的代码

七、基于AspectJ实现的AOP操作

1.什么是AspectJ

AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用进行AOP操作。

2.AOP相关术语

  • 连接点:类中可以被增强的方法,称为连接点。
  • 切入点:实际被增强的方法,称为切入点。
  • 通知:增强的那一部分逻辑代码。通知有多种类型:
    (1)前置通知:增强部分代码在原代码前面。
    (2)后置通知:增强部分代码在原代码后面。
    (3)环绕通知:增强部分代码既有在原代码前面,也有在原代码后面。
    (4)异常通知:原代码发生异常后才会执行。
    (5)最终通知:类似与finally那一部分
  • 切面:指把通知应用到切入点这一个动作。

3.切点表达式

  • 语法:execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
  • 例1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.auguigu.dao.BookDao.add(..))
  • 例2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.*(..))
  • 例3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.*.* (..))

3.基于注解方式实现

(1)实例:

User:
注解方式创建User对象user

package com.dragon.springaop.anno;import org.springframework.stereotype.Component;@Component
public class User {public void add(){System.out.println("add....");}
}

UserProxy类(先忽略@Order注解):
注解方式创建UserProxy对象userProxy
@Aspect定义UserProxy为切面类(即指把通知应用到切入点的类)

package com.dragon.springaop.anno;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;@Component
@Aspect//定义切面类
@Order(3)
public class UserProxy {@Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void before(){System.out.println("before.....");}@AfterReturning(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void afterReturning(){System.out.println("afterReturning....");}@After(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void after(){System.out.println("after....");}@AfterThrowing(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void afterThrowing(){System.out.println("afterThrowing....");}@Around(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{System.out.println("环绕之前....");proceedingJoinPoint.proceed();System.out.println("环绕之后....");}
}

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.xsdhttp://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd"><!--开启组件扫描--><context:component-scan base-package="com.dragon.springaop.anno"/><!--开启AspectJ生成代理对象--><aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试:

 	ApplicationContext context=new ClassPathXmlApplicationContext("beanaop1.xml");User user=context.getBean("user", User.class);user.add();

在这里插入图片描述
可以看出Befoe(前置通知,在add前运行)、AfterRetruning(后置通知或返回通知,在add返回值后运行)、AfterThrowing(异常通知,在add出现异常后,这个没有运行,因为没异常,大家在add内添加 int i=1/0 测试一下,不在演示)、After(最终通知,在add执行完后)、Around(环绕通知,在add前和后)的运行时期。

(2)切入点提取

上面的UserProxy 类中有很多重复的切入点表达式,可以进行公共提取

@Pointcut(value = "execution(* com.dragon.springaop.anno.User.add(..))")
public void pointDemo(){    
}//前置通知
@Before(value="pointDemo()")
public void before(){System.out.println("before....");
}

(3)设置增强类优先级

上面的实例只有UserProxy一个增强类,当有多个增强类时,可以使用@Order(数值)设置优先级执行。(数字越小优先级越高)
在上诉例子中多创建一个PeopleProxy类,设置@Order:

package com.dragon.springaop.anno;import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.jupiter.api.Order;
import org.springframework.stereotype.Component;@Component
@Aspect
@Order(1)
public class PersionProxy {@Before(value = "execution(* com.dragon.springaop.anno.User.add(..))")public void persionBefore(){System.out.println("persionBefore.....");}
}

上面的UserProxy类中我设置的是Order(3),所以PeopleProxylei类先运行。
在这里插入图片描述

(4)完全注解开发

AOPConfig类:

package com.dragon.springaop.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration
@ComponentScan(basePackages = {"com.dragon.springaop"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AopConfig {
}

Book、BookProxy:

package com.dragon.springaop.aopxml;import org.springframework.stereotype.Component;@Component
public class Book {public void buy(){System.out.println("buy......");}
}========================================
package com.dragon.springaop.aopxml;public class BookProxy {public void before(){System.out.println("before....");}
}

测试:

		ApplicationContext context=new AnnotationConfigApplicationContext(AopConfig.class);Book book=context.getBean("book", Book.class);book.buy();

4.基于xml配置文件实现(了解)

Book、BookProxy:

package com.dragon.springaop.aopxml;import org.springframework.stereotype.Component;public class Book {public void buy(){System.out.println("buy......");}
}========================================
package com.dragon.springaop.aopxml;public class BookProxy {public void before(){System.out.println("before....");}
}

spring配置文件:

 <bean id="book" class="com.dragon.springaop.aopxml.Book"></bean><bean id="bookProxy" class="com.dragon.springaop.aopxml.BookProxy"></bean><!--    配置aop增强--><aop:config>
<!--        切入点--><aop:pointcut id="p" expression="execution(* com.dragon.springaop.aopxml.Book.buy(..))"/>
<!--        配置切面--><aop:aspect ref="bookProxy">
<!--            增强作用在具体的方法上--><aop:before method="before" pointcut-ref="p"></aop:before></aop:aspect></aop:config>

测试:

		ApplicationContext context=new ClassPathXmlApplicationContext("beanaop2.xml");Book book=context.getBean("book", Book.class);book.buy();

八、JdbcTemplate

1.相关依赖(AOP、IOC、JdbcTemplate都有)

        <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>spring</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>19</maven.compiler.source><maven.compiler.target>19</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>compile</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.9.2</version><scope>compile</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>6.0.9</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.16</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version><scope>runtime</scope></dependency><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><dependency><groupId>net.sourceforge.cglib</groupId><artifactId>com.springsource.net.sf.cglib</artifactId><version>2.1.3</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.0.9</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>6.0.9</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>compile</scope></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.19</version></dependency></dependencies>
</project>

2.代码实战

(1)方法讲解

  • 增删改:
int update(String sql, Object... args);
  • 查询(返回某个值):
T queryForObject(String sql,Class<T> requiredType);
  • 查询(返回某个对象):
T queryForObject(String sql,Class<T> requiredType);
  • 查询(返回集合):
List<T> query(String sql,RowMapper<T> rowMapper,Object... args);
  • 批量增删改:
int[] batchUpdate(String sql,List<Object[]> batchArgs);

(2)代码实例

实体层——Book实体类:

package com.dragon.jdbc.entity;public class Book {private String bookId;private String bookname;private String bstatus;public String getBookId() {return bookId;}public String getBookname() {return bookname;}public String getBstatus() {return bstatus;}public void setBookId(String bookId) {this.bookId = bookId;}public void setBookname(String bookname) {this.bookname = bookname;}public void setBstatus(String bstatus) {this.bstatus = bstatus;}@Overridepublic String toString() {return "Book{" +"bookId='" + bookId + '\'' +", bookname='" + bookname + '\'' +", bstatus='" + bstatus + '\'' +'}';}
}

Dao层——BookDao类:

package com.dragon.jdbc.dao;import com.dragon.jdbc.entity.Book;import java.util.List;public interface BookDao {public void add(Book book);//添加public void update(Book book);//修改更新public void delete(String id);//删除public int selectCount();//查找数量,返回int类型public Book findBookInfo(String id);//根据id查找某本书,返回对象public List<Book> findAllBook();//查找数据库内所有对象,返回集合public void bathAddBook(List<Object[]> bathArgs);//批量添加public void bathUpdateBook(List<Object[]> bathArgs);//批量修改public void bathDeleteBook(List<Object[]> bathArgs);//批量删除
}

BookDao实现类BookDaoImpl:

package com.dragon.jdbc.dao;import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;import java.util.Arrays;
import java.util.List;@Repository
public class BookDaoImpl implements BookDao{@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void add(Book book) {String sql="insert into t_book values(?,?,?)";Object[] args={book.getBookId(),book.getBookname(),book.getBstatus()};int update=jdbcTemplate.update(sql,args);System.out.println(update);}@Overridepublic void update(Book book) {String sql="update t_book set bookname=?,bstatus=? where book_id=?";Object[] args={book.getBookname(),book.getBstatus(),book.getBookId()};int update=jdbcTemplate.update(sql,args);System.out.println(update);}@Overridepublic void delete(String id) {String sql="delete from t_book where book_id=?";int update=jdbcTemplate.update(sql,id);System.out.println(update);}@Overridepublic int selectCount() {String sql="select count(*) from t_book";Integer count=jdbcTemplate.queryForObject(sql,Integer.class);return count;}@Overridepublic Book findBookInfo(String id) {String sql="select * from t_book where book_id=?";Book book= jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id);return book;}@Overridepublic List<Book> findAllBook() {String sql="select * from t_book";List<Book> bookList=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class));return bookList;}@Overridepublic void bathAddBook(List<Object[]> bathArgs) {String sql="insert into t_book values(?,?,?)";int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);System.out.println(Arrays.toString(ints));}@Overridepublic void bathUpdateBook(List<Object[]> bathArgs) {String sql="update t_book set bookname=?,bstatus=? where book_id=?";int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);System.out.println(Arrays.toString(ints));}@Overridepublic void bathDeleteBook(List<Object[]> bathArgs) {String sql="delete from t_book where book_id=?";int[] ints=jdbcTemplate.batchUpdate(sql,bathArgs);System.out.println(Arrays.toString(ints));}}

service层——BookService:

package com.dragon.jdbc.service;import com.dragon.jdbc.dao.BookDao;
import com.dragon.jdbc.entity.Book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class BookService {@Autowiredprivate BookDao bookDao;public void addBook(Book book){bookDao.add(book);}public void updateBook(Book book){bookDao.update(book);}public void deleteBook(String id){bookDao.delete(id);}public int findCount(){return bookDao.selectCount();}public Book finOne(String id){return bookDao.findBookInfo(id);}public List<Book> findAll(){return bookDao.findAllBook();}public void bathAdd(List<Object[]> bathArgs){bookDao.bathAddBook(bathArgs);}public void bathUpdate(List<Object[]> bathArgs){bookDao.bathUpdateBook(bathArgs);}public void bathDelete(List<Object[]> bathArgs){bookDao.bathDeleteBook(bathArgs);}
}

数据库连接配置——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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean><context:component-scan base-package="com.dragon.jdbc"></context:component-scan>
</beans>

properties配置文件——jdbc.properties:
需要自行修改数据库名称(我的是user_db)

pro.driverClass=com.mysql.cj.jdbc.Driver
pro.url=jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
pro.username=root
pro.password=root

测试类:

package com.dragon.jdbc.test;import com.dragon.jdbc.entity.Book;
import com.dragon.jdbc.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.ArrayList;
import java.util.List;public class test1 {public static void main(String[] args) {ApplicationContext context=new ClassPathXmlApplicationContext("bean8.xml");BookService bookService=context.getBean("bookService",BookService.class);
//        Book book=new Book();
//        book.setBookId("1");
//        book.setBookname("java");
//        book.setBstatus("a");
//        bookService.addBook(book);//        Book book=new Book();
//        book.setBookId("1");
//        book.setBookname("javaup");
//        book.setBstatus("a");
//        bookService.updateBook(book);//        bookService.deleteBook("1");//        System.out.println( bookService.findCount());//        Book book=bookService.finOne("1");
//        System.out.println(book);//        System.out.println(bookService.findAll());//        List<Object[]> bathArgs=new ArrayList<>();
//        Object[] o1={"3","java","j"};
//        Object[] o2={"4","c++","c"};
//        Object[] o3={"5","MySql","m"};
//        bathArgs.add(o1);
//        bathArgs.add(o2);
//        bathArgs.add(o3);
//        bookService.bathAdd(bathArgs);//        List<Object[]> bathArgs=new ArrayList<>();
//        Object[] o1={"java001","j","3"};
//        Object[] o2={"c++002","c","4"};
//        Object[] o3={"MySql003","m","5"};
//        bathArgs.add(o1);
//        bathArgs.add(o2);
//        bathArgs.add(o3);
//        bookService.bathUpdate(bathArgs);List<Object[]> bathArgs=new ArrayList<>();Object[] o1={"3"};Object[] o2={"4"};bathArgs.add(o1);bathArgs.add(o2);bookService.bathDelete(bathArgs);}}

九、事务及其参数含义

1.事务的四个特性

  • 原子性
  • 一致性
  • 隔离性
  • 持久性。

2.事务的传播行为(propagation)

Spring定义了7种传播行为:

传播属性描述
REQUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则,就启动一个新的事务,并在自己的事务内运行
REQUIRED_NEW当前的方法必须启动新事务,并在它自己的事务内运行,如果有事务正在运行,应该将它挂起
SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中
NOT_SUPPORTED当前方法不应该运行在事务中,如果有运行的事务,将它挂起
MANDATORY当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常
NESTED如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行

在这里插入图片描述
这里只图解介绍一个,其他类推

3.事务隔离性

  • 脏读:一个未提交事务读取到另一个未提交事务的数据
    例:事务A读取到事务B修改后的数据,但是读取后事务B回滚了,此时A读取的是修改后的数据,但是修改撤销了。
  • 不可重复读:一个未提交的事务读取到另一个提交事务修改数据
    例:事务A和事务B读取同一个数据,但是事务B在读取后进行修改,然后提交,提交后事务A又读取这个数据,此时读取的是修改后的,跟上次读取的不一样。
  • 幻读(虚读):一个未提交的事务读取到另一个提交事务添加数据

4.事务的隔离级别(ioslation)

在这里插入图片描述

5.timeout(超时)

事务在一定时间内进行提交,如果不提交会进行回滚,默认值是-1,设置时间以秒为单位进行计算。

6.readOnly(是否只读)

读:查询,写:增删改
默认值是false,表示可以增删改查,设置true后只能查询。

7.rollbackFor(回滚)

设置出现哪些异常进行事务回滚。

8.noRollbackFor(不回滚)

设置出现哪些异常不进行事务回滚。

十、事务管理

Spring事务管理提供了一个接口,叫做事务管理器,这个接口针对不同的框架提供不同的实现类。
在这里插入图片描述

1.事务管理的两种形式

  • 编程式事务管理
    例:
        try{//开启事务//进行业务操作userDao.reduceMoney();//模拟异常int i=10/0;userDao.addMoney();//没出现异常,事务提交}catch (Exception e){//异常,事务回滚}
  • 声明式事务管理(AOP原理)
    例:
@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{@Autowiredprivate UserDao userDao;public void accountMoney(){userDao.reduceMoney();int i= 1 / 0;userDao.addMoney();}
}

2.注解实现声明式事务管理

就是上述声明式管理的例子,这里补充一下全部代码:

================userDao====================
package com.dragon.shiwu.dao;public interface UserDao {public void addMoney();public void reduceMoney();
}
==============userDaoImpl===================
package com.dragon.shiwu.dao;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;@Repository
public class UserDaoImpl implements UserDao{@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void addMoney() {String sql="update t_account set money=money + ? where username = ?";jdbcTemplate.update(sql,100,"mary");}@Overridepublic void reduceMoney() {String sql="update t_account set money=money-? where username=?";jdbcTemplate.update(sql,100,"lucy");}
}
==============userService============================
package com.dragon.shiwu.service;import com.dragon.shiwu.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class UserService{@Autowiredprivate UserDao userDao;public void accountMoney(){userDao.reduceMoney();int i= 1 / 0;userDao.addMoney();}
}
============Spring配置文件===========================(注意这里引入了tx命名空间和)
<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean>
<!--创建JdbcTemplate对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><!--注入数据库连接池--><property name="dataSource" ref="dataSource"></property></bean><context:component-scan base-package="com.dragon.shiwu"></context:component-scan>
<!--创建事务管理器--><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>

运行前:
在这里插入图片描述
运行后:
在这里插入图片描述
在这里插入图片描述

3.xml实现声明式事务管理

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: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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop.xsd"><context:property-placeholder location="classpath:jdbc.properties"/><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${pro.driverClass}"></property><property name="url" value="${pro.url}"></property><property name="username" value="${pro.username}"></property><property name="password" value="${pro.password}"></property></bean><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean>
<!--    开启组件扫描--><context:component-scan base-package="com.dragon.shiwu"></context:component-scan><!--配置事务通知--><tx:advice id="txadvice"><tx:attributes><!--配置事务参数--><tx:method name="accountMoney" propagation="REQUIRED"/></tx:attributes></tx:advice><!--    配置切入点和切面--><aop:config>
<!--        配置切入点--><aop:pointcut id="pt" expression="execution(* com.dragon.shiwu.service.UserService.*(..))"/>
<!--        配置切面--><aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor></aop:config>
</beans>

4.完全注解开发

TxConfig类:

package com.dragon.shiwu.config;import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration//配置类
@ComponentScan(basePackages = "com.dragon.shiwu")//组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {//创建数据库连接池@Beanpublic DruidDataSource getDruidDataSource(){DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");druidDataSource.setUrl("jdbc:mysql://localhost:3306/user_db");druidDataSource.setUsername("root");druidDataSource.setPassword("root");return druidDataSource;}//创建JdbcTemplate对象@Beanpublic JdbcTemplate getJdbcTemplate(DataSource dataSource){JdbcTemplate jdbcTemplate = new JdbcTemplate();jdbcTemplate.setDataSource(dataSource);return jdbcTemplate;}//创建事务管理器@Beanpublic DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();transactionManager.setDataSource(dataSource);return transactionManager;}}

测试类:

package com.dragon.shiwu.test;import com.dragon.shiwu.config.TxConfig;
import com.dragon.shiwu.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class test2 {public static void main(String[] args) {ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);UserService userService = context.getBean("userService",UserService.class);userService.accountMoney();}
}

总结

以上就是Spring的全部详细讲解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/232233.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[HTML]Web前端开发技术3(HTML5、CSS3、JavaScript )超链接,target,scrolling,marginwidth,frameborder,iframe——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

c语言:[输出函数]与[输入函数]|要点简述

一、【输出函数】 printf() 与 puts()的不同点 1、printf()函数 printf()支持单个字符%c的输出&#xff0c;以及字符串%s的输出。 (1)如果是以%c的形式输出&#xff0c;是一个字符一个字符的输出。因此&#xff0c;要用一个循环语句&#xff0c;把字符逐个输出。 (2)而用%…

骨传导耳机和气传导耳机有什么区别?谁更值得入手?

先说答案&#xff0c;骨传导耳机和气传导耳机的佩戴方式和传声方式不同&#xff0c;并且骨传导耳机相比于气传导耳机更值得入手。 一、骨传导耳机和气传导耳机有什么区别 1、佩戴方式不同 骨传导耳机采用一体式耳挂佩戴或耳夹式佩戴&#xff0c;气传导耳机采用分体式耳挂设计…

羊大师揭秘,皮肤保湿不如喝点羊奶?

羊大师揭秘&#xff0c;皮肤保湿不如喝点羊奶&#xff1f; 在寒冷的冬季&#xff0c;人们常常会发现自己的皮肤变得干燥、粗糙&#xff0c;甚至出现裂纹。而这时候&#xff0c;大家或许很难联想到喝点羊奶能够改善这一问题。但是小编羊大师发现&#xff0c;事实上羊奶确实可以…

前端开发中的webpack打包工具

前端技术发展迅猛&#xff0c;各种可以提高开发效率的新思想和框架层出不穷&#xff0c;但是它们都有一个共同点&#xff0c;即源代码无法直接运行&#xff0c;必须通过转换后才可以正常运行。webpack是目前主流的打包模块化JavaScript的工具之一。 本章主要涉及的知识点有&am…

高中python语言常用语句,高中python教程标准

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;高中python语言常用语句&#xff0c;高中python教程标准&#xff0c;现在让我们一起来看看吧&#xff01; 大家好&#xff0c;本文将围绕高中python语言常用语句展开说明&#xff0c;高中python例题和答案是一个很多人都…

Axure之交互与情节与一些实例

目录 一.交互与情节简介 二.ERP登录页到主页的跳转 三.ERP的菜单跳转到各个页面的跳转 四.省市联动 五.手机下拉加载 今天就到这里了&#xff0c;希望帮到你哦&#xff01;&#xff01;&#xff01; 一.交互与情节简介 "交互"通常指的是人与人、人与计算机或物体…

第二证券:股票交易时间以及规则是什么?

股票生意时间以及规则是什么&#xff1f; 1、股票生意时间 周一至周五上午9&#xff1a;30-11:30&#xff0c;下午13:00-15:00&#xff0c;周末以及法定节假日休市不进行生意。可是不生意不代表不能进行托付&#xff0c;股票在清算之后投资者就能够进行托付。股票的清算时间&…

一招教你将logo背景变透明,省时又方便!

透明背景的Logo可以与不同的背景颜色或图像融合&#xff0c;而不会出现突兀或不协调的感觉&#xff0c;这使得Logo在各种媒体和设计中更加灵活和多用途&#xff0c;想要把图片去背景变透明的方法有很多&#xff0c;比如最常见的就是利用ps软件来处理&#xff0c;不过这个图片去…

308 Permanent Redirect的一种可能解决方案:检查一下请求路径

两条斜线导致请求可能自动定向到https了&#xff1f;反正给改成一条斜线就好了

我的4096创作纪念日

机缘 岁月如梭&#xff0c;时光一晃已经在CSDN扎根4096天了。第一次注册CSDN好像还是在2012年&#xff0c;那会还没大学毕业。初入CSDN&#xff0c;只是把他当作自己编程时遇到问题的在线笔记记录而已&#xff0c;没想到无意间还帮助了其他遇到同样问题困扰的同学。而在这4096…

uni-data-checkbox无法选中

问题描述 今天在使用uni-data-checkbox时候发现文字选中了&#xff0c;单选的小圆圈没有出来。在浏览器模拟手机显示的效果和在安卓手机上显示的效果都和下面的图一样。 错误代码 <uni-data-checkbox mode"list" v-model"chooseLanguage" :localdata…

【CCF CSP】202312-2 因子化简(C/C++解题思路+满分题解)

解题思路 80分思路代码 由于题目在数据规模中说明阈值k > 1, 因此提取因式时只需要关注次数在二次以上的因式。也就是说&#xff0c;我们只需要判断从1到待化简因式的平方根是否是满足题意的因式即可。举个例子&#xff0c;假设题目所给因式是10000&#xff0c;那么只需要判…

docker 限制ip访问端口

需求限制外网访问 docker的某个服务 经过查找 发现 ubuntu的 ufw 防火墙是无效的 技术交流http://idea.coderyj.com/ 1.查看docker的 路由 iptables --line -nvL DOCKER-USER默认是允许所有的访问不限制 2.添加限制规则 iptables 是从上往下匹配的所以我们限制规则要在第一条 …

格密码与线性代数

目录 一. 幺模矩阵 二. Gram-Schmidt 正交化 三. 矩阵分解 四. 格基本区 五. 对偶格基 六. 矩阵伪逆 七. 正定矩阵 八. 矩阵转置 九. 奇异值分解&#xff08;SVD分解&#xff09; 格密码中格基是矩阵&#xff0c;格点是向量。本文章梳理一些格密码常用到的一些线性代数…

Unity 如何通过2D Sprite切割一张图为多张

1、理解 在一些2D游戏开发中&#xff0c;我们常常使用2D Sprite把一张大图切割成多个小图使用。 这样做有不少好处&#xff0c;首先&#xff0c;通过精准使用小图&#xff0c;能够一定程度上节省内存&#xff0c;提高渲染性能。 其次把同类的小图做成一张大图在切割使用会更…

ElasticSearch详细搭建以及常见错误high disk watermark [ES系列] - 第497篇

导读 历史文章&#xff08;文章累计490&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六…

Java毕业设计——基于SpringBoot的健身房管理系统

1&#xff0c;项目背景 随着人们生活水平的提高和健康意识的增强&#xff0c;健身行业逐渐兴起并迅速发展。而现代化的健身房管理系统已经成为健身房发展的必备工具之一。传统的健身房管理方式已经无法满足现代化健身房的需求&#xff0c;需要一种更加高效、智能、安全的管理系…

HamronyOS 自动化测试框架使用指南

概述 为支撑 HarmonyOS 操作系统的自动化测试活动开展&#xff0c;我们提供了支持 JS/TS 语言的单元及 UI 测试框架&#xff0c;支持开发者针对应用接口进行单元测试&#xff0c;并且可基于 UI 操作进行 UI 自动化脚本的编写。 本指南重点介绍自动化测试框架的主要功能&#x…

欧非源国际交易平台在2023中非经济贸易大湾区论坛首次亮相

12月16日&#xff0c;2023中非经济贸易大湾区论坛在鹏城隆重召开&#xff0c;欧非源国际交易平台首次亮相。来自非洲部分国家的驻华使节、中非经济贸易委员会领导以及商&#xff08;协&#xff09;会、企业家代表共同见证了欧非源国际交易平台的发布&#xff0c;亲历了该平台与…