安装
Gradle 引用org.mybatis:mybatis:3.5.11
引用MySQL:mysql:mysql-connector-java
使用
配置
在resouces文件夹下先新建org/mybatis文件夹,再新建mybatis-config.xml文件和config.properties文件
mybatis-config.xml如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="org/mybatis/config.properties"/> // 下面的配置可以使用${xxx}代替硬编码
<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> // 该属性可以开启自动映射 </settings>
<typeAliases> <typeAlias type="com.cyh.server.domain.User" alias="User"/> // 类路径,简写 </typeAliases>
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <package name="com.cyh.server.db.mapper"/> // resources下的路径 </mappers> </configuration>
|
config.properties如下
1 2 3 4
| driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis_test?useUnicode=true&characterEncoding=utf8 username=root password=
|
Spring 配置代码
1 2 3 4 5 6 7 8 9 10 11
| @Configuration public class MyBatisConfiguration {
@Bean public SqlSessionFactory sqlSessionFactory() throws IOException { String resource = "org/mybatis/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); }
}
|
创建Mapper
开始创建方法,假设我们在com.cyh.server.db.mapper下创建mapper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public interface UserMapper {
User selectUser(Long id);
Long insertUser(User user);
}
@Data public class User { Long id; String name; String hashedPassword; }
|
则需要在resources文件下,创建同路径的mapper文件:
如下:resources/com/cyh/server/db/mapper/UserMapper.xml
⚠️注意:在创建resources下的文件夹时,和创建包路径不一样,不能简单填写”com.cyh.server.db.mapper”,否则会创建一个名为”com.cyh.server.db.mapper”的文件夹,可以填”com/cyh/server/db/mapper”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.cyh.server.db.mapper.UserMapper"> <resultMap id="usermap" type="User"> // 这里type可以简写,因为上述的typeAliases <id column="id" property="id"/> <result column="name" property="name"/> <result column="hashed_password" property="hashedPassword"/> </resultMap> <select id="selectUser" resultMap="usermap"> // id和方法名一样,resultMap是结果映射 select * from User where id = #{id} </select>
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyColumn="id" keyProperty="id"> // 使用自增id,参数的类型是实体类 INSERT INTO `user` (`id`, `name`, `hashed_password`) VALUES (#{id}, #{name}, #{hashedPassword}) </insert> </mapper>
|
在Spring使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Repository public class UserRepository {
@Autowired private SqlSessionFactory sessionFactory;
public User findById(Long id) { try (SqlSession session = sessionFactory.openSession()) { UserMapper mapper = session.getMapper(UserMapper.class); return mapper.selectUser(id); } }
public Long addUser(User user) { try (SqlSession session = sessionFactory.openSession()) { UserMapper mapper = session.getMapper(UserMapper.class); Long ret = mapper.insertUser(user); session.commit(); return ret; } }
}
|
常用代码段
批量插入insertAll
1 2 3 4 5 6 7
| <insert id="insertAll" useGeneratedKeys="true" keyColumn="id" keyProperty="id" parameterType="xxx"> INSERT INTO <include refid="TableName"/> (c1, c2) values <foreach collection="list" item="item" separator=","> (#{item.f1}, #{item.f2}) </foreach> </insert>
|
相关问题
if标签字符串判断相等问题
1 2 3 4 5 6
| <if test="a == '1'.toString()"> AND db_field != '-1' </if> <if test='a == "2"'> AND db_field = '-1' </if>
|
模糊查询
1
| name like concat("%", #{name}, "%")
|
原理分析
启动解析
XMLConfigBuilder
入口: XMLConfigBuilder#parseConfiguration
- mappers节点,child有package和其他,package指定resource下的路径,其他类型支持resource、url、mapperClass三个属性之一
- resource、url对应一个单独的mapper.xml文件,通过
XMLMapperBuilder.parse()解析
- parse之后得到
Configuration对象 - 通过
Configuration构建SqlSessionFactory
XMLMapperBuilder
解析Mapper.xml文件的mapper标签内容
- cache-ref: 复用其他namespace下的cache
- cache: 构建二级缓存
- namespace
- parameterMap(已废弃): 构建
ParameterMapping, - resultMap: 构建
ResultMap - sql
- select|insert|update|delete:通过
XMLStatementBuilder处理
XMLStatementBuilder
- 处理
include - 对于insert和update,处理
selectKey,每个selectKey对应一个MappedStatement XMLScriptBuilder#parseDynamicTags: 对每个语句进行切割- 纯文本部分为
StaticTextSqlNode - 有
${}或类似<where>标签的,为TextSqlNode或WhereSqlNode - 最后组合成
MixedSqlNode,通过XMLScriptBuilder构造对应的DynamicSqlSource或RawSqlSource
- 处理标签上其他属性
- 优先使用
SelectKeyGenerator - 最终得到
MappedStatement对象
结果处理
涉及到的技术
- Java反射
- JDK动态代理
- XML解析
- OGNL表达式解析
涉及的设计模式
建造者模式
工厂模式
DataSourceFactorySqlSessionFactoryTransactionFactoryMapperProxyFactory
模板方法模式
- 各种
StatementHandler实现 - 各种
Executor实现 - 很多接口都有一个
BaseXXInterface抽象实现
组合模式
- 对于
SqlNode,有各种实现,并且有MixedSqlNode实现可以作为组合
装饰者模式
CachingExecutor可包装其他Executor
适配器模式
代理模式
策略模式
- 在
DefaultSqlSessionFactory里使用Executor,configuration.newExecutor