简介
MyBatis是一个轻量级的ORM框架,它简化了对关系数据库的使用,开发人员可以在XML或注解中编写SQL来完成对数据库的操作。
如果完全使用XML方式,SQL语句可以集中维护,做到与Java代码完全隔离,便于对SQL调优。
原理及流程
- 加载配置:配置来源于两个地方,一是配置文件,一是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
- SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参。
- SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
- 结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。
技术盏
反射、jdk动态代理、Ognl表达式引擎、缓存
反射和动态代理
解析是将SQL或存储过程定义表述为Mybatis中对应对象的过程,例如将执行的Sql标签( , …)解析为 MappedStatement ;输入参数定义标签解析为 ParameterMap ;结果列定义标签解析为 ResultMap
Mybatis支持将一个类的方法映射到一个 mapper 文件里的对应 statement sql,将方法名与DML SQL标签的id对应起来,这样我们就可以透明地使用 interface 的方式结合了面向对象的方式来与数据库操作,这样做更趋近于面向对象的编程风格。其中用到jdbc动态代理原理,用 MapperProxy 动态代理了需要执行的接口方法,主要代理逻辑在 MapperMethod 中实现,负责用接口的名称以及方法名称找到解析好的 MappedStatement 然后调用 SqlSession 中对应的执行逻辑执行。
缓存
Mybatis的一级缓存是SqlSession级别。第一次执行select时候会发现sqlsession缓存没有记录,会去数据库查找,然后把结果保存到缓存,第二次同等条件查询下,就会从缓存中查找到结果。另外为了避免脏读,每次执行更新新增删除时候会清空当前sqlsession缓存。
二级缓存是namespace级别的。同一个namespace下的搜寻语句共享一个二级缓存。如果开启了二级缓存,则先从二级缓存中查找,查找不到则委托为SimpleExecutor查找,而它则会先从一级缓存中查找,查找不到则从数据库查找。
mybaits的二级缓存一般不怎么使用,默认一级缓存是开启的。
#基于注解方式的demo
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_name` varchar(100) DEFAULT NULL,
`create_time` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.4.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
application.properties
project.name=mybatis
server.port=7005
management.port=7006
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=123
logging.level.root=info
mybatis.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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 我们不会将这个Bean进行实例化,class属性中定义了PropertyPlaceholderConfigurer类,可以告诉Spring我们实际上要注册一个properties文件-->
<bean id="propertyFileConfigForDB"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:application.properties</value>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 声明式事物控制 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactor" class="org.mybatis.spring.SqlSessionFactoryBean" primary="true">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 ,包下的类需要使用@MapperScan注解,否则容器注入会失败 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.dao.*"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactor"/>
</bean>
</beans>
主类上添加注解 @ImportResource({“classpath:mybatis.xml”}),以引入配置mybatis.xml
public class UserDo {
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
private Long id;
private String user_name;
private Long create_time;
private Integer age;
public UserDo() {}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public Long getCreate_time() {
return create_time;
}
public void setCreate_time(Long create_time) {
this.create_time = create_time;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
@MapperScan
public interface UserMapper {
@Insert("insert into user (user_name,create_time,age) values ("
+ "#{user_name},#{create_time},#{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
Long insertUser(UserDo userDo);
@Delete("delete from user where id = #{id}")
Long deleteUser( Long id);
@Update("update user set user_name=#{user_name}, create_time=#{create_time},"
+ " age=#{age} where id=#{id}")
Long updateUser(UserDo userDo);
@Select("select * from user where id=#{id}")
UserDo selectUserById(Long id);
}
public interface UserService {
Long createUser(User user);
Long deleteUser(Long id);
Long updateUser(User user);
User selectUser(Long id);
}
@Service
public class UserServiceImpl implements UserService {
private static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
@Resource
private UserMapper userMapper;
@Override
public Long createUser(User user) {
try {
return userMapper.insertUser(new UserDo(user));
} catch (Exception ex) {
logger.error("exception occurred: {}", ex);
}
return null;
}
@Override
public Long deleteUser(Long id) {
try {
return userMapper.deleteUser(id);
} catch (Exception ex) {
logger.error("exception occurred: {}", ex);
}
return null;
}
@Override
public Long updateUser(User user) {
try {
return userMapper.updateUser(new UserDo(user));
} catch (Exception ex) {
logger.error("exception occurred: {}", ex);
}
return null;
}
@Override
public User selectUser(Long id){
try {
UserDo userDo = userMapper.selectUserById(id);
return new User(userDo);
} catch (Exception ex) {
logger.error("exception occurred: {}", ex);
}
return null;
}
}
通过maven插件自动生成entity、mapper
<generatorConfiguration>
<classPathEntry location="etc\mybatis-generator\mysql-connector-java-5.1.46.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>
<plugin type="com.itfsw.mybatis.generator.plugins.BatchInsertPlugin"/>
<plugin type="com.xxx.finance.commons.service.mybatis.generator.plugin.MySQLPaginationPlugin"></plugin>
<commentGenerator>
<property name="addRemarkComments" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://xx.xx.xxx.xxx:xxxx/risk_alpha_engine"
userId="xxxxx" password="xxxxx">
</jdbcConnection>
<javaModelGenerator targetPackage="com.xxx.fin.phecda.strategy.dal.entity" targetProject="src/main/java"/>
<sqlMapGenerator targetPackage="sql" targetProject="src/main/resources"/>
<javaClientGenerator targetPackage="com.xxx.fin.phecda.strategy.dal.mapper" targetProject="src/main/java"
type="com.xxx.finance.commons.service.mybatis.generator.MySimpleJavaMapperGenerator"/>
<table tableName="sys_rule_element_rel" enableUpdateByPrimaryKey="false" enableDeleteByPrimaryKey="false" enableDeleteByExample="false"/>
<table tableName="flow_strategy_log" enableUpdateByPrimaryKey="false" enableDeleteByPrimaryKey="false" enableDeleteByExample="false"/>
<table tableName="sys_biz_flow_version" enableUpdateByPrimaryKey="true" enableDeleteByPrimaryKey="false" enableDeleteByExample="false"/>
</context>
</generatorConfiguration>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
<configurationFile>${basedir}/etc/mybatis-generator/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<dependency>
<groupId>com.xxx.finance</groupId>
<artifactId>commons-service-mybatis</artifactId>
<version>1.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.itfsw</groupId>
<artifactId>mybatis-generator-plugin</artifactId>
<version>1.0.5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
sharding-sphere分表分库
https://tomoya92.github.io/2020/06/03/sharding-sphere-horizontal-split/
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-namespace</artifactId>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
参考资料
入门+原理
https://zhuanlan.zhihu.com/p/34446308
https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247483937&idx=1&sn=85727e94ad3d1af1ef99cfefa420520c&chksm=ebd74320dca0ca367f869427202eb029bf3cf8dd4dc71dae26d925aaaabc2c8ea704735b3b87&scene=21###wechat_redirect