一.前言
我是一个五年得java开发工程师,在印象里,从第一年我就会使用mybatis了,从最开始得xml配置,到spring整合,再到springboot。无非就是写个mapper抽象类,写个mapper.xml方法。就这么一直用着。期间也想看看这么优秀得框架是怎么生成的。奈何工作缠身。最近比较闲,打算整理一下。那么我们现在开始。
二.准备阶段
pom中添加依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
如果想连接mysql加上
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
三.开干
(1)两种构建方式创建SqlSessionFactory
1.xml方式
在resource里面添加一个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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
main方法中直接上:
public static void main(String[] args) {
InputStream resourceAsStream = null;
try {
resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
}
2.java配置方式
PooledDataSource pooledDataSource = new PooledDataSource("com.mysql.cj.jdbc.Driver", "jdbc:mysql://127.0.0.1:3306/test", "root", "123456");
JdbcTransactionFactory jdbcTransactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", jdbcTransactionFactory, pooledDataSource);
Configuration configuration = new Configuration(environment);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
(2)获取Sqlsession
SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
SqlSession sqlSession = sqlSessionFactory.openSession();
里面有各种查询方法
老版本的写法
List<Map<String, Object>> animals = sqlSession.selectList("com.chen.mybatis.selectAnimal");
这里面的“com.chen.xxxxxxx”在哪呢?
首先你得在上面提到的mybatis-config.xml 中添加一个标签
<mappers>
<mapper resource="animalMapper.xml"/>
</mappers>
然后在resources目录下创建一个anmalMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chen.mybatis">
<select id="selectAnimal" resultType="java.util.Map">
select * from animal
</select>
</mapper>
namespace + select id 就是代码里面的参数了。
新版本写法
AnimalMapper mapper = sqlSession.getMapper(AnimalMapper.class);
List<Animal> animals = mapper.selectList();
AnimalMapper 接口
@Mapper
public interface AnimalMapper {
List<Animal> selectList();
@Select("select name from animal where id = #{id}")
String selectNameById(int id);
}
这个selectNameById 就是在java注解里面写sql了,我不太喜欢这样。不过多说明了。
四.作用域
SqlSessionFactoryBuild 是为了创建SqlSessionFacory的 最佳作用域是方法作用域
SqlSessionFactory 最好就创建一个
SqlSession 是线程不安全的,最佳作用域是请求或方法作用域,绝对不能把她放到一个静态域里面。
五.xml配置
这部分配置信息读者老爷们直接去官网看把
https://mybatis.org/mybatis-3/zh/configuration.html
六.类型处理器 typeHandlers
MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。
觉得好玩的应该是自定义类型处理器
你可以重写已有的类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler
接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler
, 并且可以(可选地)将它映射到一个 JDBC 类型。比如:
xml配置文件里面添加如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chen.mybatis.AnimalMapper">
<resultMap id="BaseResultMap" type="com.chen.mybatis.Animal">
<constructor>
<idArg column="id" javaType="java.lang.Integer" jdbcType="INTEGER"/>
<arg column="name" javaType="java.lang.String" jdbcType="VARCHAR"/>
<arg column="age" javaType="java.lang.Integer" jdbcType="INTEGER"/>
<arg column="types" typeHandler="com.chen.mybatis.MyTypeHandler" javaType="java.util.List" jdbcType="VARCHAR"/>
</constructor>
</resultMap>
<select id="selectList" resultMap="BaseResultMap">
select * from animal
</select>
</mapper>
注: 这个xml只能放到和mapper接口相同的目录下,要不不好用哦
package com.chen.mybatis;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.rocketmq.shaded.commons.lang3.StringUtils;
import org.apache.rocketmq.shaded.io.grpc.netty.shaded.io.netty.util.internal.StringUtil;
import java.sql.*;
import java.util.Arrays;
import java.util.List;
/**
* @Title: MyTypeHandler
* @Description:
* @author: chenyulei
* @date: 2023/10/10 10:50
*/
//这个注解定义的是JdbcType类型,这里的类型不可自己随意定义,必须要是枚举类org.apache.ibatis.type.JdbcType所枚举的数据类型
@MappedJdbcTypes(JdbcType.VARCHAR)
//这里定义的是JavaType的数据类型,描述了哪些Java类型可被拦截
@MappedTypes({List.class})
public class MyTypeHandler extends BaseTypeHandler<List<String>> {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, List<String> parameter, JdbcType jdbcType) throws SQLException {
String hobbys= StringUtils.join(parameter,",");
try {
preparedStatement.setString(i,hobbys);
} catch (SQLException e) {
e.printStackTrace();
}
}
@Override
public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return Arrays.asList(rs.getString(columnName).replace("[","").replace("]","").split(","));
}
@Override
public List<String> getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
return Arrays.asList(resultSet.getString(columnIndex).replace("[","").replace("]","").split(","));
}
@Override
public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return Arrays.asList(cs.getString(columnIndex).replace("[","").replace("]","").split(","));
}
}
上面代码就是把varchar类型的types,返回回来处理成了List<String>。
七.插件(plugins)
你总想在sql执行期间打印一些东东,那我们就可以使用拦截器咯
package com.chen.mybatis;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.Properties;
/**
* @Title: SelectPlugins
* @Description:
* @author: chenyulei
* @date: 2023/10/11 15:36
*/
@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class})})
public class SelectPlugins implements Interceptor {
private Properties properties = new Properties();
@Override
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object proceed = invocation.proceed();
System.out.println("拦截select方法");
return proceed;
}
}
别忘了在配置类里面添加
configuration.setMapUnderscoreToCamelCase(true);
configuration.addInterceptor(updatePlugins);