Mybatis源码学习一
1.创建Mybatis的相关依赖:
<?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>MyBatisDemo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--添加Spring依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.2.RELEASE</version> </dependency> <!--添加Spring-JDBC依赖 --> <!--提供了数据库连接池--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.1.RELEASE</version> </dependency> <!--添加Mybatis依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency> <!--添加Mybatis-Spring依赖--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <!-- 加入MySQL依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.15</version> </dependency> <!--添加日志依赖--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.8.0-beta4</version> </dependency> <!--添加log4j依赖 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> </project>
2.创建配置类:
1 package com.wk.app; 2 3 import org.apache.ibatis.logging.log4j.Log4jImpl; 4 import org.apache.ibatis.session.SqlSessionFactory; 5 import org.mybatis.spring.SqlSessionFactoryBean; 6 import org.mybatis.spring.annotation.MapperScan; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.ComponentScan; 9 import org.springframework.context.annotation.Configuration; 10 import org.springframework.jdbc.datasource.DriverManagerDataSource; 11 12 import javax.sql.DataSource; 13 14 /** 15 * 配置类 16 */ 17 @Configuration 18 @ComponentScan("com.wk") 19 @MapperScan("com.wk.dao")//作用是扫描添加了@Mapper注解的类 20 public class APPConfig { 21 22 /** 23 * 创建数据源 24 * @return 25 */ 26 @Bean 27 public DataSource dataSource(){ 28 DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(); 29 driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver"); 30 driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC"); 31 driverManagerDataSource.setUsername("root"); 32 driverManagerDataSource.setPassword("root"); 33 return driverManagerDataSource; 34 } 35 36 /** 37 * 创建SqlSessionFactoryBean实例 38 * @return 39 * @throws Exception 40 */ 41 @Bean 42 public SqlSessionFactory sqlSessionFactory() throws Exception { 43 SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); 44 factoryBean.setDataSource(dataSource()); 45 //通过编码方式设置mybatis的配置 46 /*org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); 47 configuration.setLogImpl(Log4jImpl.class); 48 factoryBean.setConfiguration(configuration);*/ 49 return factoryBean.getObject(); 50 } 51 }
3.创建Mapper接口,并实现查询语句:
1 package com.wk.dao; 2 3 import com.wk.entity.Seckill; 4 import org.apache.ibatis.annotations.Param; 5 import org.apache.ibatis.annotations.Select; 6 7 import java.math.BigInteger; 8 9 public interface SeckillMapper { 10 11 @Select("SELECT * FROM seckill WHERE seckill_id = #{seckillId}") 12 Seckill querySeckillById(@Param("seckillId") BigInteger seckillId); 13 }
4.创建service注入Mapper依赖:
1 @Service("seckillService") 2 public class SeckillServiceImpl implements SeckillService { 3 //注入依赖 4 @Autowired 5 SeckillMapper seckillMapper; 6 7 public Seckill getSeckillById(BigInteger seckillId) { 8 return seckillMapper.querySeckillById(seckillId); 9 } 10 }
5.创建测试类:
1 /** 2 * 测试类 3 */ 4 public class Test { 5 public static void main(String[] args) { 6 //org.apache.ibatis.logging.LogFactory.useLog4JLogging(); 7 ApplicationContext context = new AnnotationConfigApplicationContext(APPConfig.class); 8 SeckillService service = (SeckillService) context.getBean("seckillService"); 9 System.out.println(service.getSeckillById(new BigInteger("1000"))); 10 } 11 }
到这里,一个完整的mybatis功能就完成了。
mybatis实现sql语句日志打印的方式(有两种):
第一种:
1.创建log4j.properties,参考mybatis官网
1 # Global logging configuration 2 log4j.rootLogger=DEBUG,stdout 3 # MyBatis logging configuration...设置sql语句的打印作用域 4 #log4j.logger.org.mybatis.example.BlogMapper=TRACE 5 log4j.logger.com.wk.dao.SeckillMapper.querySeckillById=TRACE 6 # Console output... 7 log4j.appender.stdout=org.apache.log4j.ConsoleAppender 8 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 9 log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
2.引入log4j的依赖:
<!-- 引入log4j的依赖--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
3.在test类中加入执行方法org.apache.ibatis.logging.LogFactory.useLog4JLogging();:
1 /** 2 * 测试类 3 */ 4 public class Test { 5 public static void main(String[] args) { 6 //日志打印sql执行语句 7 org.apache.ibatis.logging.LogFactory.useLog4JLogging(); 8 ApplicationContext context = new AnnotationConfigApplicationContext(APPConfig.class); 9 SeckillService service = (SeckillService) context.getBean("seckillService"); 10 System.out.println(service.getSeckillById(new BigInteger("1000"))); 11 } 12 }
第二种:
通过编码的方式,来对程序进行控制,添加日志打印功能
使用Configuration 类的setLogImpl(Log4jImpl.class);方法进行功能实现。
1 /** 2 * 配置类 3 */ 4 @Configuration 5 @ComponentScan("com.wk") 6 @MapperScan("com.wk.dao")//作用是扫描添加了@Mapper注解的类 7 public class APPConfig { 8 9 /** 10 * 创建数据源 11 * @return 12 */ 13 @Bean 14 public DataSource dataSource(){ 15 DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(); 16 driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver"); 17 driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/seckill?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC"); 18 driverManagerDataSource.setUsername("root"); 19 driverManagerDataSource.setPassword("root"); 20 return driverManagerDataSource; 21 } 22 23 /** 24 * 创建SqlSessionFactoryBean实例 25 * @return 26 * @throws Exception 27 */ 28 @Bean 29 public SqlSessionFactory sqlSessionFactory() throws Exception { 30 SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); 31 factoryBean.setDataSource(dataSource()); 32 //通过编码方式设置mybatis的配置 33 org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); 34 configuration.setLogImpl(Log4jImpl.class); 35 factoryBean.setConfiguration(configuration); 36 return factoryBean.getObject(); 37 } 38 }
Mybatis在于spring整合之后,一级缓存失效的原因是什么?
因为mybatis和spring整合之后,spring就会管理mybatis用于数据库查询的sqlSession,spring对这个sqlSession进行扩展,使用一个sqlSessionTemplate类做了一个代理,这个类在spring容器启动的时候注入给了Mapper,这个类代替了原来Mybatis包中自己的DefaultSqlSession类,所以这个sqlSession就在这个代理对象中了,每次查询完之后,spring就会通过这个代理对象来关闭sqlSession,所以即便是相同的查询语句,mybatis每次都要使用新的sqlSession建立连接进行查询,查询完之后,这个sqlSession就被spring容器关闭了,所以导致mybatis的一级缓存失效。
Mybatis的二级缓存的缺点:
Mybatis的二级缓存是基于命名空间的,也就是说,只有在一个Mapper类下的方法,如果一个查询方法和一个更新方法不在同一个Mapper类下进行的,那么mybatis的二级缓存就会忽视更新之后的数据,仍然使用之前的缓存,导致数据错误。