SpringMVC整合Mybatis-Junit-Self4j
SpringMVC整合Mybatis
步骤:
- 导入相关依赖
- Spring核心依赖
- Spring-MVC核心依赖
- Mybatis核心依赖
- MySQL数据库驱动依赖
- 注意Mysql的版本和驱动版本保持一致
- Druid数据库连接池依赖
- MySQL数据库驱动依赖
- Spring-Mybatis整合依赖
- 会自动导入Spring-mabtis、Spring-jdbc和spring-tx依赖
<dependencies>
<!--Spring核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!--SpringMVC核心依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!--整合Mybatis-->
<!--1. Mysql数据库驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!--2. 连接池依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<!--3. mybatis本身的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--4. 整合mybatis和spring的依赖-->
<!--MyBatis提供的和Spring进行整合的jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--spring对jdbc封装的jar包也要导入进来,否则mybatis无法整合-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.2.RELEASE</version>
</dependency>
<!--编译时DispatcherServlet的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
-
在配置文件中配置数据库连接信息jdbc.properties
-
driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/learn?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true db-username=root password=root
-
-
编写mapper接口实现对数据库操作
-
@Mapper注解可加可不加
-
@Mapper public interface UserMapper { @Select("select * from user where id=#{id}") User getUserById(int id); @Select("select * from user") List<User> getAllUser(); }
-
-
在Spring容器配置类中扫描mapper接口所在的包
-
并通过配置文件创建数据源和sqlSession工厂,将mybatis相关对象交给spring容器进行管理
-
@Configuration @ComponentScan(basePackages = {"server"}) @MapperScan(basePackages = "mapper") @PropertySource("classpath:jdbc.properties") public class SpringConfig { @Value("${driver}") String driver; @Value("${url}") String url; /* 这里在测试的时候使用的是username,不过username被解析为默认值即电脑名称而不是配置文件中配置的值 原因如下: username 和 password 被系统属性或环境变量覆盖,如果系统属性或环境变量中存在 username,Spring 会优先使用这些值,而不是从 jdbc.properties 中读取。 */ @Value("${db-username}") String username; @Value("${password}") String password; @Bean public DataSource dataSource(){ DruidDataSource dataSource = new DruidDataSource(); // 基本配置 dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } @Bean @Autowired public SqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource){ SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean(); sqlSessionFactory.setDataSource(dataSource); /*加载xml文件的位置 // 指定 Mapper XML 文件的位置 sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml") ); // 调用 getObject() 返回 SqlSessionFactory 实例 return sessionFactory.getObject(); */ return sqlSessionFactory; } }
-
-
在Server相关类中注入mapper接口,调用mapper接口的方法完成对数据库的操作
-
@Service public class UserServer { @Autowired UserMapper userMapper; public String getUser(){ User user=userMapper.getUserById(1); String str=user.toString(); return str; } }
-
事务管理
默认行为:
- JDBC 连接的默认行为
- 在 JDBC 中,连接的默认行为是 自动提交事务(
autoCommit=true)。 - 这意味着,如果没有显式地开启事务,每个 SQL 语句都会立即提交到数据库。
- 在 JDBC 中,连接的默认行为是 自动提交事务(
- Spring 整合 MyBatis 的情况
- 如果没有配置任何事务管理器(如
DataSourceTransactionManager),Spring 不会介入事务管理。 - MyBatis 会直接使用底层的 JDBC 连接,因此每个 SQL 语句会立即提交。
- 如果没有配置任何事务管理器(如
- 如果配置了事务管理器,确保事务管理器和mybatis使用的是统一个数据库源
- 共享数据源:事务管理器和 MyBatis 通常共享同一个数据源。这样,事务管理器可以管理 MyBatis 使用的数据库连接,确保事务的一致性。
- 事务管理器的优先级:事务管理器会覆盖 MyBatis 的默认事务行为。如果配置了事务管理器,MyBatis 会使用事务管理器管理的事务,而不是 MyBatis 的默认行为。
配置事务管理器:
-
将事务管理器Bean配置在Spring容器中:
-
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
-
-
启动注解驱动
-
区分spring-config和web-config场景需要注意
- 注意配置该注解驱动上的配置类中,配置的包扫描中要能扫到
@Transactional注解
- 注意配置该注解驱动上的配置类中,配置的包扫描中要能扫到
-
@Configuration @EnableTransactionManagement public class AppConfig { }
-
-
使用
@Transactional注解管理事务-
@Service public class UserService { @Autowired private UserMapper userMapper; @Transactional public void createUser(User user) { userMapper.insert(user); throw new RuntimeException("Test exception"); // 抛出异常 } }
-
事务传播行为
-
默认行为
-
默认的传播行为是
REQUIRED,即如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。 -
@Transactional public void methodA() { // 开启事务 methodB(); // 调用方法 B // 提交或回滚事务 } @Transactional(propagation = Propagation.REQUIRED) public void methodB() { // 在方法 A 的事务中执行 }
-
-
嵌套事务
- 如果方法 A 调用方法 B,且方法 B 的传播行为是
REQUIRES_NEW,则方法 B 会开启一个新事务,方法 A 的事务会被挂起。 - 如果方法 B 的传播行为是
NESTED,则方法 B 会在方法 A 的事务中创建一个嵌套事务。 REQUIRES_NEW创建的新事务是独立的,如果方法 B 回滚,不会影响方法 A 的事务。
- 如果方法 A 调用方法 B,且方法 B 的传播行为是
事务超时行为
-
默认行为
- 默认情况下,事务没有超时限制。
-
设置超时
-
可以通过
@Transactional注解的timeout属性设置事务的超时时间(单位:秒)。 -
@Transactional(timeout = 10) public void updateUser(User user) { userMapper.update(user); } -
超时回滚:如果事务在超时时间内未完成,Spring 会回滚事务。
-
性能影响:设置合理的超时时间,避免长时间占用数据库资源。
-
事务的只读属性
-
默认行为
- 默认情况下,事务是可读写的。
-
设置只读
-
可以通过
@Transactional注解的readOnly属性将事务设置为只读。 -
@Transactional(readOnly = true) public User getUserById(int id) { return userMapper.selectById(id); } -
性能优化:只读事务可以优化数据库的性能,因为数据库不需要为写操作维护锁。
-
写操作禁止:在只读事务中执行写操作会抛出异常。
-
事务的失效场景
-
@Transactional注解只能用于 public 方法。如果将其应用于非 public 方法(如protected、private或包级私有方法),事务不会生效。- 确保
@Transactional注解仅用于 public 方法。
- 确保
-
如果方法 A 调用同一个类中的方法 B,且方法 B 有
@Transactional注解,事务不会生效。这是因为 Spring 的事务管理是基于代理的,自调用不会经过代理。-
@Service public class UserService { public void createUser(User user) { insertUser(user); // 自调用,事务失效 } @Transactional public void insertUser(User user) { userMapper.insert(user); } } -
解决方法
-
将方法 B 移到另一个类中:
-
@Service public class UserService { @Autowired private UserHelper userHelper; public void createUser(User user) { userHelper.insertUser(user); // 通过依赖注入调用 } } @Service public class UserHelper { @Autowired private UserMapper userMapper; @Transactional public void insertUser(User user) { userMapper.insert(user); } }
-
-
使用
AopContext.currentProxy():-
@Service public class UserService { public void createUser(User user) { ((UserService) AopContext.currentProxy()).insertUser(user); // 通过代理调用 } @Transactional public void insertUser(User user) { userMapper.insert(user); } }
-
-
-
-
如果在事务方法中捕获了异常但没有重新抛出,事务不会回滚。默认情况下,Spring 只会在遇到运行时异常(
RuntimeException)时回滚事务。- 在捕获异常后重新抛出,或使用
@Transactional注解的rollbackFor属性指定回滚的异常类型。
- 在捕获异常后重新抛出,或使用
-
如果事务方法被
final或static修饰,事务不会生效。这是因为 Spring 的事务管理是基于动态代理的,无法代理final或static方法。- JDK 动态代理基于接口实现,要求目标类必须实现至少一个接口。
- CGLIB 动态代理基于继承实现,通过生成目标类的子类来创建代理对象。
- 被代理的方法要求是从接口中实现的方法或者可以继承的方法,所以final方法无法被代理
- static方法是类级别的,所以无法被代理
Junit
作用:
- 自动加载Spring容器而无需手动加载
- 运行demo方法
流程:
-
导入依赖
-
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
-
-
编写测试类,通过注解指定Spring容器的位置
-
通过自动注入导入Spring容器中的Bean即可测试
-
注意测试方法需要@Test注解
-
@RunWith(SpringJUnit4ClassRunner.class) //@ContextConfiguration(value = {"classpath:applicationContext.xml"}) // 指定配置文件 @ContextConfiguration(classes = SpringConfig.class) // 指定配置类 public class junitTest { @Autowired public UserServer userServer; @Test public void test(){ String user = userServer.getUser(); System.out.println(user); } }
-
Slf4j
作用:
- 日志框架
流程:
-
导入相关依赖
-
<!-- Log4j2核心库 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.1</version> </dependency> <!-- Log4j2 API --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.14.1</version> </dependency> <!-- 可选:SLF4J 绑定 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>2.14.1</version> </dependency> -
创建logger对象,该对象不需要交给Spring容器进行管理
-
import org.slf4j.Logger; import org.slf4j.LoggerFactory; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfig.class) // 指定配置类 public class junitTest { private static final Logger logger = LoggerFactory.getLogger(junitTest.class); @Autowired public UserServer userServer; @Test public void test(){ String user = userServer.getUser(); System.out.println(user); logger.debug("This is a debug message."); } } -
注意:导入的一定是org.slf4j包下的相关组件
-

浙公网安备 33010602011771号