Spring 概述 HelloSpring 创建对象的方式 Spring配置 Bean的自动装配 使用注解开发 代理模式 AOP 整合Mybatis 声明式事务 注解式事务

Maven引入

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.3</version>
</dependency>

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.3</version>
</dependency>

HelloSpring

实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    private Integer id;
    private String username;
    private String password;
}

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"> 
    <!--bean就是java对象 , 由Spring创建和管理-->
    <!--id为获取唯一标识-->
    <bean >
        <property name="id" value="1"/>
        <property name="username" value="admin"/>
        <property name="password" value="admin"/>
    </bean>
</beans>

测试

@Test
public void hello() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//    User user = context.getBean("user", User.class);
    User user = (User) context.getBean("user");
    System.out.println(user);
}

创建对象的方式

在配置文件加载的时候。其中管理的对象都已经初始化了

set注入

创建对象:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private String name;
    private Teacher teacher;
    private String[] books;
    private List<String> hobbies;
    private Map<String, String> cards;
    private Set<String> games;
    private String wife;
    private Properties infos;
}

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

常量注入

<bean >
    <property name="name" value="李老师"/>
</bean>

bean注入

<bean >
    <property name="name" value="张三"/>
    <!--引用类型用ref,引用Spring容器里的id-->
    <property name="teacher" ref="teacher"/>
</bean>

数组注入

<bean >
    <property name="name" value="张三"/>
    <property name="teacher" ref="teacher"/>
    <property name="books">
        <array>
            <value>西游记</value>
            <value>红楼梦</value>
            <value>水浒传</value>
        </array>
    </property>
</bean>

List注入

<property name="hobbies">
    <list>
        <value>听歌</value>
        <value>看电影</value>
        <value>爬山</value>
    </list>
</property>

Map注入

<property name="cards">
    <map>
        <entry key="工商银行" value="123"/>
        <entry key="农业银行" value="456"/>
    </map>
</property>

Set注入

<property name="games">
    <set>
        <value>魔兽世界</value>
        <value>星际争霸</value>
        <value>英雄联盟</value>
    </set>
</property>

Null注入

<property name="wife"><null/></property>

Properties注入

<property name="infos">
    <props>
        <prop key="age">14</prop>
        <prop key="gender">男</prop>
        <prop key="address">北京</prop>
    </props>
</property>

构造器注入

<!--构造器index下标-->
<bean >
    <!--从0开始-->
    <constructor-arg index="0" value="1"/>
    <constructor-arg index="1" value="admin1"/>
    <constructor-arg index="2" value="123"/>
</bean>
<!--构造器参数名字-->
<bean >
    <constructor-arg name="id" value="2"/>
    <constructor-arg name="username" value="admin2"/>
    <constructor-arg name="password" value="123"/>
</bean>
<!--构造器参数类型-->
<bean >
    <constructor-arg type="java.lang.Integer" value="3"/>
    <!--参数类型相同时按顺序赋值-->
    <constructor-arg type="java.lang.String" value="admin3"/>
    <constructor-arg type="java.lang.String" value="123"/>
</bean>

扩展注入

P命名空间注入

导入约束 : xmlns:p="http://www.springframework.org/schema/p" 

<!--P(属性: properties)命名空间 , 属性依然要设置set方法--> 
<bean />

C命名空间注入

导入约束 : xmlns:c="http://www.springframework.org/schema/c" 

<!--C(构造: Constructor)命名空间 , 属性依然要设置set方法--> 
<bean />

Spring配置

别名

<alias name="user" alias="userAlias"/>

Bean的配置

别名

<!--id唯一标识符,name别名-->
<bean >
    <property name="id" value="1"/>
    <property name="username" value="admin"/>
    <property name="password" value="admin"/>
</bean>

作用域

<bean >
    <property name="id" value="1"/>
</bean>

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

import

导入其他Spring配置文件,合并为一个配置文件

<import resource="bean1.xml"/>
<import resource="bean2.xml"/>

Bean的自动装配

  • 自动装配是使用spring满足bean依赖的一种方法
  • spring会在应用上下文中为某个bean寻找其依赖的bean

Spring中bean有三种装配机制,分别是:

  1. 在xml中显式配置;
  2. 在java中显式配置;
  3. 隐式的bean发现机制和自动装配。

byName

<bean >
    <property name="name" value="李老师"/>
</bean>
<bean >
    <property name="name" value="张三"/>
</bean>

当一个bean节点带有 autowire byName 的属性时

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
  2. 去spring容器中寻找是否有此字符串名称id的对象。
  3. 如果有,就取出注入;如果没有,就报空指针异常。

byType

<bean class="com.demo.entity.Teacher">
    <property name="name" value="李老师"/>
</bean>
<bean >
    <property name="name" value="张三"/>
</bean>

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

使用注解

准备工作:

  1. 在spring配置文件中引入context文件头
xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
  1. 开启属性注解支持
<context:annotation-config/>

@Autowired

  • @Autowired是按类型自动装配的,不支持id匹配
  • 有多个同类型时尝试按set id byName匹配,没有则报错

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

@Autowired(required = false) // required = false 表示对象可以为null
private Teacher teacher;

@Qualifier

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
  • @Qualifier不能单独使用
@Autowired()
@Qualifier("teacher1") // 指定id
private Teacher teacher;

@Resource

  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
  • 其次再进行默认的byName方式进行装配;
  • 如果以上都不成功,则按byType的方式自动装配;
  • 都不成功(多个同类型),则报异常。
@Resource(name = "teacher1")
private Teacher teacher;

使用注解开发

在spring4之后,想要使用注解形式,必须得要引入aop的包

引入context约束:

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

开启包扫描

<!--开启注解支持-->
<context:annotation-config/>
<!--开启包扫描,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.demo.entity"/>

bean注入

@Component

@Component("teacher1") // 等价于 <bean />,默认id为类名首字母小写
public class Teacher {
    private String name;
}

@Repository

dao层

@Controller

web层

@Service

service层

属性注入

@Value

@Value("李老师")
private String name;

@Autowired

@Scope作用域

@Component
@Scope("prototype")
public class Teacher {
}

基于Java类进行配置

可以省去配置文件

新建类

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
// 不自动纳入容器
public class Dog {
    private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component // 自动纳入Spring容器
public class Teacher {
    @Value("李老师")
    private String name;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component // 自动纳入Spring容器
public class Student {
    @Value("张三")
    private String name;
    @Resource
    private Teacher teacher;
}

新建配置类

@Configuration // 代表这是一个配置类
@ComponentScan("com.demo.entity") // 扫描其他包下的自动Bean
@Import(MyConfig.class) //导入合并其他配置类,类似于配置文件中的 import 标签
public class AppConfig {

    @Bean// 通过方法手动注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id
    public Dog dog() {
        return Dog.builder().name("旺财").build();
    }

    @Bean("dog1")// 也可以自定义bean名
    public Dog dog() {
        return Dog.builder().name("旺财1").build();
    }
}

测试

@Test
public void test() {
    // 从配置类获取上下文环境
    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    Dog dog = context.getBean("dog", Dog.class);
    System.out.println(dog);
    Teacher teacher = context.getBean("teacher", Teacher.class);
    System.out.println(teacher);
    Student student = context.getBean("student", Student.class);
    System.out.println(student);
}

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

代理模式

静态代理

租房案例

Rent接口:

public interface Rent {
    /**
     * 出租房子
     */
    void rent();
}

房东:

public class Host implements Rent{
    /**
     * 出租房子
     */
    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

中介:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Proxy implements Rent {
    private Host host;

    /**
     * 出租房子
     */
    @Override
    public void rent() {
        seeHouse();
        host.rent();
    }

    public void seeHouse() {
        System.out.println("中介带你看房");
    }
}

客户:

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
//        host.rent();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

新增日志案例

UserService:

public interface UserService {
    void getUser();
    void addUser();
}

UserServiceImpl:

public class UserServiceImpl implements UserService{
    
    @Override
    public void getUser() {
        System.out.println("获取用户");
    }

    @Override
    public void addUser() {
        System.out.println("新增用户");
    }
}

UserServiceProxy:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserServiceProxy {
    private UserService userService;

    public void getUser() {
        log("使用了getUser方法");
        userService.getUser();
    }
    public void addUser() {
        log("使用了addUser方法");
        userService.addUser();
    }

    public void log(String msg) {
        System.out.println(msg);
    }
}

Client:

public class Client {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
//        userService.getUser();
//        userService.addUser();
        UserServiceProxy userServiceProxy = new UserServiceProxy(userService);
        userServiceProxy.getUser();
        userServiceProxy.addUser();
    }
}

动态代理

  • 动态代理的角色和静态代理的一样 .
  • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
  • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
    • 基于接口的动态代理----JDK动态代理
    • 基于类的动态代理--cglib
    • 现在用的比较多的是 javasist 来生成动态代理 .

JDK的动态代理需要了解两个类

  • 核心:InvocationHandlerProxy

核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!

处理类

public class ProxyInvocationHandler implements InvocationHandler {
    // 被代理的接口
    private Object target;

    public ProxyInvocationHandler(Object target) {
        this.target = target;
    }

    // 生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    // 处理代理实例,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("中介带你看房");
        Object result = method.invoke(target, args);
        System.out.println("签订合同");
        return result;
    }
}

动态生成代理对象

public class Client2 {
    public static void main(String[] args) {
        // 真实角色
        Host host = new Host();

        // 设置要代理的对象
        ProxyInvocationHandler pih = new ProxyInvocationHandler(host);

        // 生成代理角色
        Rent rent = (Rent) pih.getProxy();
        rent.rent();
    }
}

AOP

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

需要导入一个包

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

通过 Spring API 实现

AOP的约束

xmlns:aop="http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

新建Active类

public class BeforeLog implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + "的" + method.getName() + "执行前");
    }
}
public class AfterLog implements AfterReturningAdvice {

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了" + method.getName() + ",返回结果为:" + returnValue);
    }
}

配置文件配置

<!--注册bean-->
<bean />
<bean />
<bean />

<!--配置aop-->
<!--方式一:使用原生Spring API接口-->
<aop:config>
    <!--配置切入点-->
    <aop:pointcut />
    <!--配置环绕-->
    <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>

测试

public class ClientAop {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 动态代理代理的是接口
        UserService userService = context.getBean("userService", UserService.class);
        userService.getUser();
        userService.addUser();
    }
}

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

自定义类

新建切面类

public class MyAspect {
    public void before() {
        System.out.println("===方法执行前===");
    }
    public void after() {
        System.out.println("===方法执行后===");
    }
}

配置文件配置

<!--方式二:自定义切面-->
<!--引入自定义切面类-->
<bean />
<aop:config>
    <!--切面配置-->
    <aop:aspect ref="myAspect">
        <!--切入点配置-->
        <aop:pointcut />
        <!--环绕配置-->
        <aop:before method="before" pointcut-ref="pointcut"/>
        <aop:after method="after" pointcut-ref="pointcut"/>
    </aop:aspect>
</aop:config>

测试

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

使用注解实现

新建切面类

@Aspect
public class AnnotationAspect {
    @Before("execution(* com.demo.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("===AnnotationAspect执行前===");
    }
    @After("execution(* com.demo.service.UserServiceImpl.*(..))")
    public void after() {
        System.out.println("===AnnotationAspect执行后===");
    }
    @Around("execution(* com.demo.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        System.out.println(jp.getSignature());
        // 执行方法
        Object proceed = jp.proceed();
        System.out.println(proceed);

        System.out.println("环绕后");
    }
}

配置文件配置

<!--方式三:注解-->
<!--引入自定义切面类-->
<bean />
<!--开启注解支持-->
<aop:aspectj-autoproxy/>

测试

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

整合Mybatis

Maven引入

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <!--MyBatis相关-->
    <dependency><!--数据库驱动-->
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.22</version>
    </dependency>
    <dependency><!--mybatis-->
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <dependency><!--mybatis-spring整合-->
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>
    <!--MyBatis相关-->
    <!--spring相关-->
    <dependency><!--Spring核心-->
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.3</version>
    </dependency>
    <dependency><!--事务-->
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.3</version>
    </dependency>
    <dependency><!--AOP-->
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.6</version>
    </dependency>
    <!--spring相关-->
</dependencies>

<build>
    <!-- 防止资源导出错误 -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <!--开启日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--开启下划线转驼峰-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <!--别名配置-->
    <typeAliases>
        <package name="com.demo.entity"/>
    </typeAliases>
    
    <!--Mapper注册-->
    <mappers>
        <package name="com.demo.mapper"/>
    </mappers>
</configuration>

appcationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!--加载Properties配置文件-->
    <context:property-placeholder location="classpath:db.properties"/>

    <!--DataSource-->
    <!--使用Spring的数据源-->
    <bean >
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>

    <!--SqlSessionFactory-->
    <bean >
        <property name="dataSource" ref="dataSource" />
        <!--绑定mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!--以下两个配置需要再增加一个实现类-->
    <!--sqlSession-->
    <!--<bean >-->
    <!--    <constructor-arg ref="sqlSessionFactory"/>-->
    <!--</bean>-->

    <!--注册userMapperImpl-->
    <!--<bean >-->
    <!--    <property name="sqlSession" ref="sqlSession"/>-->
    <!--</bean>-->

    <!--不需要增加实现类-->
    <!--MapperFactoryBean 将会负责 SqlSession 的创建和关闭-->
    <bean >
        <property name="mapperInterface" value="com.demo.mapper.UserMapper"/>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

</beans>

*新增加的实现类:

public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    /**
     * 获取全部用户
     */
    @Override
    public List<User> getUserList() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUserList();
    }
}

测试

@Test
public void testGetUserList() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
    List<User> userList = userMapper.getUserList();
    for (User user : userList) {
        System.out.println(user);
    }
}

声明式事务

新增事务约束

xmlns:tx="http://www.springframework.org/schema/tx"

http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx.xsd">

配置事务管理器

<!--配置事务管理器-->
<bean >
    <property name="dataSource" ref="dataSource"/>
</bean>

配置事务环绕

<!--配置事务环绕-->
<tx:advice >
    <tx:attributes>
        <!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
        <tx:method name="add" propagation="REQUIRED"/>
        <tx:method name="delete" propagation="REQUIRED"/>
        <tx:method name="update" propagation="REQUIRED"/>
        <tx:method name="search*" propagation="REQUIRED"/>
        <tx:method name="get" read-only="true"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

Spring
概述
HelloSpring
创建对象的方式
Spring配置
Bean的自动装配
使用注解开发
代理模式
AOP
整合Mybatis
声明式事务
注解式事务

配置aop

<!--配置aop织入事务-->
<aop:config>
    <aop:pointcut />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

测试

public class UserServiceImpl {
    private UserMapper userMapper;

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public void test() {
        userMapper.addUser(new User(10, "root10", "root10"));
        int i = 10/0;
        userMapper.deleteUser(10);
    }
}
<bean >
    <property name="userMapper" ref="userMapper"/>
</bean>
@Test
public void testTransaction() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserServiceImpl userService = context.getBean("userService", UserServiceImpl.class);

    userService.test();
}

结果:出错事务回滚,没有插入进去

注解式事务