目录
MyBatis 是一个开源、轻量级的数据持久化框架,是 JDBC 和 Hibernate 的替代方案。MyBatis 内部封装了 JDBC,简化了加载驱动、创建连接、创建 statement 等繁杂的过程,开发者只需要关注 SQL 语句本身。
配置文件:
mybatis-config.xml需要注意的点:
映射要保持对应
现在需要根据 url 和 name来模糊查询网站信息,显然这涉及到了两个参数。给映射器传递多个参数分为以下三种方法。
(1).使用Map传递参数
使用 MyBatis提供的 Map接口作为参数。
在WebsiteMapper.xml中定义
- <!-- 根据name和url模糊查询网站信息 -->
- <select id="selectWebsiteByMap"
- resultType="com.apesource.entity.Website"
- parameterType="map">
- SELECT id,NAME,url FROM website
- WHERE name LIKE CONCAT ('%',#{name},'%')
- AND url LIKE CONCAT ('%',#{url},'%')
- </select>
在 WebsiteMapper 接口中,定义方法selectWebsiteByMap:
public List<Website> selectWebsiteByMap(Map<String, String> params);
使用 Map 传递参数虽然简单易用,但是由于这样设置参数需要键值对应,业务关联性不强,开发人员需要深入到程序中看代码,造成可读性下降。
(2). 使用注解传递参数
使用 MyBatis 的注解 @Param() 传递参数
WebsiteMapper.xml
- <!-- 根据name和url模糊查询网站信息 -->
- <select id="selectWebsiteByAn" resultType="com.apesource.entity.Website">
- SELECT id,NAME,url FROM website
- WHERE name LIKE CONCAT ('%',#{name},'%')
- AND url LIKE CONCAT ('%',#{url},'%')
- </select>
在WebsiteMapper 接口中,定义方法selectWebsiteByAn():
public List<Website> selectWebsiteByAn(@Param("name") String name, @Param("url") String url);
当我们把参数传递给后台时,MyBatis 通过 @Param 提供的名称就会知道 #{name} 代表 name 参数,提高了参数可读性。但是如果这条 SQL 拥有 10 个参数的查询,就会造成可读性下降,增强了代码复杂性。
(3). 使用JavaBean传递参数
在参数过多的情况下,MyBatis 允许组织一个 JavaBean,通过简单的 setter和 getter方法设置参数,提高可读性。
WebsiteMapper.xml
- <!-- 根据name和url模糊查询网站信息 -->
- <select id="selectWebsiteByAn" resultType="com.apesource.entity.Website">
- SELECT id,NAME,url FROM website
- WHERE name LIKE CONCAT ('%',#{name},'%')
- AND url LIKE CONCAT ('%',#{url},'%')
- </select>
WebsiteMapper.java
public List selectWebsiteByAn(Website website) ;
以上 3 种方式的区别如下:
默认情况下,使用 #{}参数语法时,MyBatis会创建 PreparedStatement参数占位符,并通过?占位符安全地设置参数。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:ORDER BY ${columnName},这个时候${}将直接在SQL语句中进行字符串的拼接。
具体区别点总结如下:
resultMap是 MyBatis 中最复杂的元素,主要用于解决实体类属性名与数据库表中字段名不一致的情况,可以将查询结果映射成实体对象。
resultMap元素的构成
- <resultMap id="" type="">
- <constructor>
- <idArg/>
- <arg/>
- constructor>
- <id/>
- <result/>
- <association property=""/>
- <collection property=""/>
- resultMap>
id 和 result 元素都有以下属性:
元素 | 说明 |
property | 映射到列结果的字段或属性。如果 POJO 的属性和 SQL 列名(column元素)是相同的,那么 MyBatis 就会映射到 POJO 上 |
column | 对应 SQL 列 |
javaType | 配置 Java 类型。可以是特定的类完全限定名或 MyBatis 上下文的别名 |
jdbcType | 配置数据库类型。这是 JDBC 类型,MyBatis 已经为我们做了限定,基本支持所有常用数据库类型 |
typeHandler | 类型处理器。允许你用特定的处理器来覆盖 MyBatis 默认的处理器。需要指定 jdbcType 和 javaType 相互转化的规则 |
resultMap 和 resultType 不能同时使用。
在结合MyBatis框架进行批处理操作时,通常使用两种方式:
(1) 使用动态SQL进行批量添加
SQL映射文件中的配置如下所示:
- <insert id="insertNewWebsiteBatch">
- INSERT INTO website (name, url, age, country, createtime)
- VALUES
- <foreach collection="list" item="website" separator=",">
- (#{website.name},#{website.url},#{website.age},#{website.country},now())
- </foreach>
- </insert>
注意:该方法的参数为List集合,将需要批量添加的数据一次性
注意:在
遍历过程中,每次迭代遍历到的是一个Website对象传入。
(2)使用MyBatis BATCH模式进行批量添加
该方式基于MyBatis的BatchExecutor对SQL语句进行批处理执行,由于MySQL的批处理执行机制要求,必须在连接字符串中添加参数rewriteBatchedStatements=true,才可以真正开启批处理机制
①SqlSession的获取
创建SqlSession的代码如下所示:
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
工具类MyBatisUtils封装代码如下
- public static SqlSession getSqlSession() {
- SqlSession session = null;
- if(factory != null ) {
- // 创建普通执行模式的SqlSession
- // 该模式下的执行器类型默认为ExecutorType.SIMPLE
- // 所以,使用的Executor执行器对象类型为SimpleExecutor
- session = factory.openSession();
- }
- return session;
- }
-
- public static SqlSession getBatchSqlSession() {
- SqlSession session = null;
- if(factory != null ) {
- // 创建批处理模式的SqlSession
- // 该模式下的执行器类型默认为ExecutorType.BATCH
- // 所以,使用的Executor执行器对象类型为BatchExecutor
- session = factory.openSession(ExecutorType.BATCH);
- }
- return session;
- }
②SQL映射
SQL映射文件
- <insert id="insertNewWebsite"
- parameterType="com.apesource.entity.Website">
- insert into
- website(name,url,age,country,createtime)values(#{name},#{url},#{age},#{country},now())
- </insert>
SQL映射接口
- // 添加新网站信息
- public int insertNewWebsite(Website site);
③批量执行
- try (SqlSession sqlSession = MyBatisUtils.getBatchSqlSession();) {
- WebsiteMapper websiteMapper = sqlSession.getMapper(WebsiteMapper.class);
-
- // 添加5w条记录
- for (int i = 0; i < 50000; i++) {
- int r = websiteMapper.insertNewWebsite(new Website());
-
- // 每1000条执行1次批处理
- if (i != 0 && i % 1000 == 0) {
- sqlSession.commit();
- }
- }
- sqlSession.commit();
- }
每1000条执行1次批处理时,如果执行sqlSession.commit()则代表本次批处理的中的所有SQL语句全部通过Executor一次性发送给MySQL执行,并清除本地缓存与操作。
由于commit()方法没有返回值,则意味着无法批量添加操作时,需要获取自动增长的主键值。此时就需要使用sqlSession.flushStatements()。代码如下:
- try (SqlSession sqlSession = MyBatisUtils.getSqlSession(ExecutorType.BATCH);) {
- WebsiteMapper websiteMapper = sqlSession.getMapper(WebsiteMapper.class);
-
- // 添加5w条记录
- for (int i = 0; i < 50000; i++) {
- int r = websiteMapper.insertNewWebsite(new Website());
-
- // 每1000条执行1次批处理
- if (i != 0 && i % 1000 == 0) {
- // 清空并执行批处理中的所有执行操作,并获取批处理执行结果
- List<BatchResult> resultList = sqlSession.flushStatements();
-
- for(BatchResult result : resultList) {
- System.out.println("\t" + result.getParameterObjects());
- }
- }
- }
- sqlSession.commit();
- }
通过执行sqlSession.flushStatements()获取批处理的BatchResult,可以获取批处理执行后的结果,该结果中包含的每个参数对象均持有数据库自动增长并回填的主键值。