最近工作中用到了mybatis的Java API方式进行开发,顺便也整理下该功能的用法,接下来会针对基本部分进行学习:

1)Java API处理一对多、多对一的用法

2)增、删、改、查的用法;

3)涉及到类型转化的用法;

4)批量修改、批量查询、批量新增的用法(介绍的方案只使用于小批量数据处理,如果大批量数据处理,还需要使用ExecutorType.BATCH)。

Mybatis官网给了具体的文档,但是并没有对以上用法具体介绍,因此在这里整理下,以便以后工作用到时,可以参考。

本章主要使用Mybatis中使用typeHandlers进行对Enum进行转化的用法(本章将结合Spring自动注入《Spring(二十三):Spring自动注入的实现方式》)

本章将分为以下几部分:

1)环境搭建(maven+mybatis+spring整合);

2)查询、批量查询;

3)新增、批量新增;

4)修改、批量修改;

5)删除、批量删除。

下面我们针对每个步骤进行详细讲解。

1)环境搭建(maven+mybatis+spring整合)

新建maven项目 Learn-Spring-01,并在pom.xml导入mybatis/spring/mysql/druid/junit包,完整的pom.xml文章如下:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5.  
  6. <groupId>com.dx.test</groupId>
  7. <artifactId>Learn-Spring-01</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <packaging>jar</packaging>
  10.  
  11. <name>Learn-Spring-01</name>
  12. <url>http://maven.apache.org</url>
  13.  
  14. <properties>
  15. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  16. <maven.compiler.source>1.8</maven.compiler.source>
  17. <maven.compiler.target>1.8</maven.compiler.target>
  18. <!--Spring版本号 -->
  19. <org.springframework.version>5.2.0.RELEASE</org.springframework.version>
  20. <org.mybatis.version>3.4.6</org.mybatis.version>
  21. <com.alibaba.version>1.1.21</com.alibaba.version>
  22. <mysql.version>8.0.11</mysql.version>
  23. </properties>
  24.  
  25. <dependencies>
  26. <dependency>
  27. <groupId>org.springframework</groupId>
  28. <artifactId>spring-webmvc</artifactId>
  29. <version>${org.springframework.version}</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.springframework</groupId>
  33. <artifactId>spring-tx</artifactId>
  34. <version>${org.springframework.version}</version>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework</groupId>
  38. <artifactId>spring-jdbc</artifactId>
  39. <version>${org.springframework.version}</version>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.springframework</groupId>
  43. <artifactId>spring-core</artifactId>
  44. <version>${org.springframework.version}</version>
  45. </dependency>
  46. <dependency>
  47. <groupId>org.springframework</groupId>
  48. <artifactId>spring-beans</artifactId>
  49. <version>${org.springframework.version}</version>
  50. </dependency>
  51. <dependency>
  52. <groupId>org.springframework</groupId>
  53. <artifactId>spring-context</artifactId>
  54. <version>${org.springframework.version}</version>
  55. </dependency>
  56. <dependency>
  57. <groupId>org.springframework</groupId>
  58. <artifactId>spring-context-support</artifactId>
  59. <version>${org.springframework.version}</version>
  60. </dependency>
  61. <dependency>
  62. <groupId>org.springframework</groupId>
  63. <artifactId>spring-aop</artifactId>
  64. <version>${org.springframework.version}</version>
  65. </dependency>
  66. <dependency>
  67. <groupId>aspectj</groupId>
  68. <artifactId>aspectjweaver</artifactId>
  69. <version>1.5.4</version>
  70. </dependency>
  71. <dependency>
  72. <groupId>aspectj</groupId>
  73. <artifactId>aspectjrt</artifactId>
  74. <version>1.5.4</version>
  75. </dependency>
  76. <!-- Sping Test相关依赖 -->
  77. <dependency>
  78. <groupId>org.springframework</groupId>
  79. <artifactId>spring-test</artifactId>
  80. <version>${org.springframework.version}</version>
  81. </dependency>
  82.  
  83. <!--MyBatis -->
  84. <dependency>
  85. <groupId>org.mybatis</groupId>
  86. <artifactId>mybatis</artifactId>
  87. <version>${org.mybatis.version}</version>
  88. </dependency>
  89. <!-- Mybatis自身实现的Spring整合依赖 -->
  90. <dependency>
  91. <groupId>org.mybatis</groupId>
  92. <artifactId>mybatis-spring</artifactId>
  93. <version>2.0.3</version>
  94. </dependency>
  95.  
  96. <!--MySql数据库驱动 -->
  97. <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
  98. <dependency>
  99. <groupId>com.alibaba</groupId>
  100. <artifactId>druid</artifactId>
  101. <version>${com.alibaba.version}</version>
  102. </dependency>
  103. <dependency>
  104. <groupId>mysql</groupId>
  105. <artifactId>mysql-connector-java</artifactId>
  106. <version>${mysql.version}</version>
  107. </dependency>
  108.  
  109. <dependency>
  110. <groupId>junit</groupId>
  111. <artifactId>junit</artifactId>
  112. <version>4.12</version>
  113. <scope>test</scope>
  114. </dependency>
  115. </dependencies>
  116. </project>

在/src/main/resources下新建jdbc.properties/mybatis-config.xml/spring-config.xml配置文件:

jdbc.properties

  1. #jdbc settings
  2. jdbc.driver=com.mysql.cj.jdbc.Driver
  3. jdbc.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
  4. jdbc.username=root
  5. jdbc.password=123456
  6.  
  7. #pool settings
  8. jdbc.pool.init=1
  9. jdbc.pool.minIdle=3
  10. jdbc.pool.maxActive=20
  11.  
  12. #jdbc.testSql=SELECT 'x'
  13. jdbc.testSql=SELECT 'x' FROM DUAL

mybatis-config.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!--配置全局属性-->
  7. <settings>
  8. <!-- 打开延迟加载的开关 -->
  9. <setting name="lazyLoadingEnabled" value="true"/>
  10. <!-- 将积极加载改为消极加载(即按需加载) -->
  11. <setting name="aggressiveLazyLoading" value="false"/>
  12. <!-- 打开全局缓存开关(二级缓存)默认值就是 true -->
  13. <setting name="cacheEnabled" value="true"/>
  14. <!--使用jdbc的getGeneratekeys获取自增主键值-->
  15. <setting name="useGeneratedKeys" value="true"/>
  16. <!--使用列别名替换别名  默认true select name as title form table; -->
  17. <setting name="useColumnLabel" value="true"/>
  18. <!--开启驼峰命名转换-->
  19. <setting name="mapUnderscoreToCamelCase" value="true"/>
  20. <!--打印sql日志-->
  21. <setting name="logImpl" value="STDOUT_LOGGING" />
  22. </settings>
  23.  
  24. <!-- 引用db.properties配置文件 -->
  25. <!--
  26. <properties resource="db.properties"/>
  27. <typeAliases>
  28. <package name="com.dx.test.model"/>
  29. </typeAliases>
  30. -->
  31.  
  32. <!-- 元素类型为 "configuration" 的内容必须匹配 "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)"。-->
  33. <typeHandlers>
  34. <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.dx.test.model.enums.ModuleType"/>
  35. <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.dx.test.model.enums.OperateType"/>
  36. <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="com.dx.test.model.enums.DataStatus"/>
  37. </typeHandlers>
  38.  
  39. <!-- 对事务的管理和连接池的配置 -->
  40. <!--
  41. <environments default="mysql_jdbc">
  42. <environment id="oracle_jdbc">
  43. <transactionManager type="JDBC"/>
  44. <dataSource type="POOLED">
  45. <property name="driver" value="${driver}"/>
  46. <property name="url" value="${url}"/>
  47. <property name="username" value="${name}"/>
  48. <property name="password" value="${password}"/>
  49. </dataSource>
  50. </environment>
  51.  
  52. <environment id="mysql_jdbc">
  53. <transactionManager type="JDBC"/>
  54. <dataSource type="POOLED">
  55. <property name="driver" value="${driver}"/>
  56. <property name="url" value="${url}"/>
  57. <property name="username" value="${name}"/>
  58. <property name="password" value="${password}"/>
  59. </dataSource>
  60. </environment>
  61. </environments>
  62. -->
  63.  
  64. <!-- 当使用了xxxMapper.xml时,需要配置这些配置 -->
  65. <!--
  66. <mappers>
  67. <mapper resource="resources/mapper/TaskAutoExecutePlanMapper.xml"/>
  68. </mappers>
  69. -->
  70. <!-- 因在Mapper类上加入了@Mapper注解,因此这个配置也不需要了。 -->
  71. <!--
  72. <mappers>
  73. <mapper class="com.dx.test.mapper.ArticleCategoryMapper"></mapper>
  74. <mapper class="com.dx.test.mapper.ArticleMapper"></mapper>
  75. </mappers>
  76. -->
  77. </configuration>

spring-config.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context-4.0.xsd ">
  9.  
  10. <!-- bean annotation driven -->
  11. <context:annotation-config />
  12. <context:component-scan base-package="com.dx.test.repository,com.dx.test.mapper,com.dx.test.service" />
  13.  
  14. <!-- 配置整合Mybatis过程 -->
  15. <!-- 配置数据库相关参数 properties的属性:${url} -->
  16. <context:property-placeholder location="classpath:jdbc.properties" />
  17. <!--
  18. <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  19. <property name="locations">
  20. <list>
  21. <value>classpath:jdbc.properties</value>
  22. </list>
  23. </property>
  24. </bean>
  25. -->
  26.  
  27. <!--2.配置连接池属性 -->
  28. <!-- 数据源配置, 使用 Druid 数据库连接池 -->
  29. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
  30. <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
  31. <property name="driverClassName" value="${jdbc.driver}" />
  32.  
  33. <!-- 基本属性 url、user、password -->
  34. <property name="url" value="${jdbc.url}" />
  35. <property name="username" value="${jdbc.username}" />
  36. <property name="password" value="${jdbc.password}" />
  37.  
  38. <!-- 配置初始化大小、最小、最大 -->
  39. <property name="initialSize" value="${jdbc.pool.init}" />
  40. <property name="minIdle" value="${jdbc.pool.minIdle}" />
  41. <property name="maxActive" value="${jdbc.pool.maxActive}" />
  42.  
  43. <!-- 配置获取连接等待超时的时间 -->
  44. <property name="maxWait" value="60000" />
  45.  
  46. <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
  47. <property name="timeBetweenEvictionRunsMillis" value="60000" />
  48.  
  49. <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
  50. <property name="minEvictableIdleTimeMillis" value="300000" />
  51.  
  52. <property name="validationQuery" value="${jdbc.testSql}" />
  53. <property name="testWhileIdle" value="true" />
  54. <property name="testOnBorrow" value="false" />
  55. <property name="testOnReturn" value="false" />
  56. <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) -->
  57. <!-- <property name="poolPreparedStatements" value="true"/> <property name="maxPoolPreparedStatementPerConnectionSize"
  58. value="20"/> -->
  59. <!-- 配置监控统计拦截的filters: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall -->
  60. <property name="filters" value="stat,wall" />
  61. </bean>
  62.  
  63. <!--3.配置SqlSessionFactory对象 -->
  64. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  65. <!--注入数据库连接池 -->
  66. <property name="dataSource" ref="dataSource" />
  67. <!--配置mybatis全局配置文件:mybatis-config.xml -->
  68. <property name="configLocation"
  69. value="classpath:mybatis-config.xml" />
  70. <!-- 因为我们这采用的是Mybatis Java API方式,因此不需要配置 -->
  71. <!--扫描entity包,使用别名,多个用;隔开 -->
  72. <!-- <property name="typeAliasesPackage" value="com.dx.test.model"/> -->
  73. <!--扫描sql配置文件:mapper需要的xml文件 -->
  74. <!-- <property name="mapperLocations" value="classpath:mapper/*.xml"/> -->
  75. </bean>
  76.  
  77. <!-- Mapper接口所在包名,Spring会自动查找其下的类 -->
  78. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  79. <property name="basePackage" value="com.dx.test.mapper" />
  80. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
  81. </bean>
  82.  
  83. <!-- 如果想对单个mapper类关联上sqlSessionFactory,可以这么使用,具体参考:http://mybatis.org/spring/getting-started.html -->
  84. <!-- <bean id="articlerMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  85. <property name="mapperInterface" value="com.dx.test.dao.mapper.ArticleMapper"
  86. /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean> -->
  87.  
  88. <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
  89. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  90. <property name="dataSource" ref="dataSource" />
  91. </bean>
  92. </beans>

在src/main/java/com.dx.test.module.enum包下新建DataStatus枚举类:

  1. package com.dx.test.model.enums;
  2.  
  3. public enum DataStatus {
  4. Living(0), // 启用
  5. UnUsed(1); // 作废
  6.  
  7. private int value;
  8.  
  9. DataStatus(int value) {
  10. this.value = value;
  11. }
  12.  
  13. public int getValue() {
  14. return this.value;
  15. }
  16. }

在src/main/java/com.dx.test.model包下创建Log.java实体类:

  1. package com.dx.test.model;
  2.  
  3. import java.util.Date;
  4.  
  5. import com.dx.test.model.enums.DataStatus;
  6.  
  7. /**
  8. * 文章分类
  9. * */
  10. public class ArticleCategory {
  11. private Integer id; //文章分类id
  12. private String title; // 文章分类名称
  13. private String imgSrc; // 文章分类banner图片
  14. private String description; // 文章分类描述
  15. private DataStatus state; // 记录状态
  16.  
  17. private String createUser; // 新建用户
  18. private String createUserId;// 新建用户id
  19. private Date createTime; // 新建时间
  20. private String updateUser; // 修改用户
  21. private String updateUserId;// 修改用户id
  22. private Date updateTime; // 修改时间
  23. private Integer version; // 乐观锁版本号
  24.  
  25. public Integer getId() {
  26. return id;
  27. }
  28. public void setId(Integer id) {
  29. this.id = id;
  30. }
  31. public String getTitle() {
  32. return title;
  33. }
  34. public void setTitle(String title) {
  35. this.title = title;
  36. }
  37. public String getImgSrc() {
  38. return imgSrc;
  39. }
  40. public void setImgSrc(String imgSrc) {
  41. this.imgSrc = imgSrc;
  42. }
  43. public String getDescription() {
  44. return description;
  45. }
  46. public void setDescription(String description) {
  47. this.description = description;
  48. }
  49. public DataStatus getState() {
  50. return state;
  51. }
  52. public void setState(DataStatus state) {
  53. this.state = state;
  54. }
  55. public String getCreateUser() {
  56. return createUser;
  57. }
  58. public void setCreateUser(String createUser) {
  59. this.createUser = createUser;
  60. }
  61. public String getCreateUserId() {
  62. return createUserId;
  63. }
  64. public void setCreateUserId(String createUserId) {
  65. this.createUserId = createUserId;
  66. }
  67. public Date getCreateTime() {
  68. return createTime;
  69. }
  70. public void setCreateTime(Date createTime) {
  71. this.createTime = createTime;
  72. }
  73. public String getUpdateUser() {
  74. return updateUser;
  75. }
  76. public void setUpdateUser(String updateUser) {
  77. this.updateUser = updateUser;
  78. }
  79. public String getUpdateUserId() {
  80. return updateUserId;
  81. }
  82. public void setUpdateUserId(String updateUserId) {
  83. this.updateUserId = updateUserId;
  84. }
  85. public Date getUpdateTime() {
  86. return updateTime;
  87. }
  88. public void setUpdateTime(Date updateTime) {
  89. this.updateTime = updateTime;
  90. }
  91. public Integer getVersion() {
  92. return version;
  93. }
  94. public void setVersion(Integer version) {
  95. this.version = version;
  96. }
  97. @Override
  98. public String toString() {
  99. return "ArticleCategory [id=" + id + ", title=" + title + ", imgSrc=" + imgSrc + ", description=" + description
  100. + "]";
  101. }
  102. }

在src/main/java/com.dx.test.mapper包下新建ArticleCategoryMapper.java mapper接口,目前该接口内容为空,在接口上添加上@Mapper注解。

  1. package com.dx.test.mapper;
  2. import org.apache.ibatis.annotations.Mapper;
  3.  
  4. public interface ArticleCategoryMapper{
  5.  
  6. }

在src/main/java/com.dx.test.mapper.sqlprovider下新建ArticleCategorySqlProvider.java mapper sql生成类:

  1. package com.dx.test.mapper.sqlprovider;
  2.  
  3. public class ArticleCategorySqlProvider {
  4.  
  5. }

在src/main/test/com.dx.test下新建测试类ArticleCategoryTest.java

  1. package com.dx.test;
  2.  
  3. import org.junit.runner.RunWith;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.test.context.ContextConfiguration;
  6. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  7.  
  8. import com.dx.test.mapper.ArticleCategoryMapper;
  9.  
  10. /**
  11. * Unit test for simple App.
  12. */
  13. @RunWith(SpringJUnit4ClassRunner.class)
  14. @ContextConfiguration({ "classpath:spring-config.xml" })
  15. public class ArticleCategroyTest {
  16. @Autowired
  17. private ArticleCategoryMapper articleCategoryMapper;
  18.  
  19. }

2)查询、批量查询

在mapper类中新建查询、批量查询接口:

  1. /**
  2. * +根据文章分类id,查询文件分类详情
  3. * @param id 文章分类id
  4. * @return 查询到的文章分类详情
  5. * */
  6. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  7. @Results(id="articleCategoryResult",value = {
  8. @Result(property = "id",column = "id",id = true),
  9. @Result(property = "title",column = "title"),
  10. @Result(property = "imgSrc",column = "img_src"),
  11. @Result(property = "status",column = "status",javaType = DataStatus.class),
  12. @Result(property = "description",column = "description"),
  13. @Result(property = "createUser",column = "create_user"),
  14. @Result(property = "createUserId",column = "create_user_id"),
  15. @Result(property = "createTime",column = "create_time"),
  16. @Result(property = "updateUser",column = "update_user"),
  17. @Result(property = "updateUserId",column = "update_user_id"),
  18. @Result(property = "updateTime",column = "update_time"),
  19. @Result(property = "version",column = "version")
  20. })
  21. @Select("select * from article_category where id=#{id}")
  22. ArticleCategory getById(Integer id);
  23.  
  24. /**
  25. * 根据id列表,查询多个文章分类,返回文章分类列表
  26. *
  27. * @param list 查询id列表
  28. * @return returnResult
  29. * */
  30. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  31. @ResultMap(value ="articleCategoryResult")
  32. @SelectProvider(type = ArticleCategorySqlProvider.class, method = "getByIds")
  33. List<ArticleCategory> getByIds(@Param("list") List<Integer> list);
  34.  
  35. /**
  36. * 根据过滤条件,查询返回满足条件的文章分类id列表
  37. *
  38. * @param articleCategory 查询条件
  39. * @return returnResult
  40. * */
  41. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  42. @Select(value="select * from `article_category` where state=#{state} and `title` like CONCAT(CONCAT('%', #{title}), '%')")
  43. List<Integer> getIdsByCondition(ArticleCategory articleCategory);
  44.  
  45. /**
  46. * +根据查询条件,查询记录。
  47. * @param articleCategory 查询条件
  48. * @return 返回查询结果
  49. * */
  50. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  51. @ResultMap(value ="articleCategoryResult")
  52. @SelectProvider(type = ArticleCategorySqlProvider.class, method = "queryList")
  53. List<ArticleCategory> queryList(ArticleCategory articleCategory);
  54.  
  55. /**
  56. * +根据查询条件,查询记录。
  57. * @param articleCategory 查询条件
  58. * @return 返回查询结果
  59. * */
  60. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  61. @ResultMap(value ="articleCategoryResult")
  62. @Select(value="select * from `article_category` where state=#{state}")
  63. List<ArticleCategory> queryListByState(DataStatus state);

查询返回Map的用法:

  1. /**
  2. * +根据查询条件,查询记录。
  3. *
  4. * @param articleCategory 查询条件
  5. * @return 返回查询结果
  6. */
  7. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  8. @ResultType(value = HashMap.class)
  9. @MapKey(value="id")
  10. @Select(value = "select * from `article_category` where state=#{state}")
  11. Map<Integer, ArticleCategory> getIdVsModelMap(DataStatus state);
  12.  
  13. /**
  14. * +根据查询条件,查询记录。
  15. *
  16. * @param articleCategory 查询条件
  17. * @return 返回查询结果
  18. */
  19. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  20. @ResultType(value = HashMap.class)
  21. // @Results(id="idVsTitleMapResult",
  22. // value= {
  23. // @Result(property = "key",column = "id"),
  24. // @Result(property = "value",column = "title")
  25. // }
  26. // )
  27. @Select(value = "select id,title from `article_category` where state=#{state}")
  28. void getIdVsTitleMap(DataStatus state);
  29.  
  30. /**
  31. * 根据条件查询记录结果,返回Map{key:id,value:title}
  32. * @param state 文章分类记录状态
  33. * @return returnResult
  34. * */
  35. @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 60000)
  36. @ResultType(value = HashMap.class)
  37. @Select(value = "select id,title from `article_category` where state=#{state}")
  38. Map<Integer,String> getIdVsTitleMapWithResultHandler(@Param("state") DataStatus state, ResultHandler<?> resultHandler);

在mapper sql provider类中新建sql帮助方法:

  1. /**
  2. * +根据id集合,获取文章分类列表 SQL
  3. *
  4. * @param map map
  5. * @return returnResult
  6. */
  7. public String getByIds(final Map<String, List<Integer>> map) {
  8. List<Integer> tmpList = map.get("list");
  9. if (tmpList == null || tmpList.isEmpty()) {
  10. return null;
  11. }
  12.  
  13. StringBuilder sql = new StringBuilder("SELECT * FROM `article_category` WHERE `id` in (");
  14. for (int i = 0; i < tmpList.size(); i++) {
  15. sql.append("#{list[" + i + "]},");
  16. }
  17. sql.deleteCharAt(sql.length() - 1);
  18. sql.append(")");
  19. sql.append(";");
  20.  
  21. return sql.toString();
  22. }
  23.  
  24. /**
  25. * 根据查询条件,查询记录
  26. *
  27. * @param articleCategory 查询条件
  28. * @return 返回查询结果
  29. * */
  30. public String queryList(ArticleCategory articleCategory) {
  31. StringBuilder sql = new StringBuilder();
  32. sql.append("select * from `article_category` where 1=1 ");
  33.  
  34. if (articleCategory.getId() != null) {
  35. sql.append(" AND `id`=#{id}");
  36. }
  37. if (articleCategory.getTitle() != null) {
  38. sql.append(" AND `title` like CONCAT(CONCAT('%', #{title}), '%')");
  39. }
  40. if(articleCategory.getState()!=null) {
  41. sql.append(" AND `state` = #{state}");
  42. }
  43. if (articleCategory.getCreateTime() != null) {
  44. sql.append(" AND `create_time` = #{createTime}");
  45. }
  46. if (articleCategory.getCreateUser() != null) {
  47. sql.append(" AND `create_user` = #{createUser}");
  48. }
  49. if (articleCategory.getCreateUserId() != null) {
  50. sql.append(" AND `create_user_id` = #{createUserId}");
  51. }
  52. if (articleCategory.getUpdateTime() != null) {
  53. sql.append(" AND `update_time` = #{updateTime}");
  54. }
  55. if (articleCategory.getUpdateUser() != null) {
  56. sql.append(" AND `update_user` = #{updateUser}");
  57. }
  58. if (articleCategory.getUpdateUserId() != null) {
  59. sql.append(" AND `update_user_id` = #{updateUserId}");
  60. }
  61. if (articleCategory.getVersion() != null) {
  62. sql.append(" AND `version` = #{version}");
  63. }
  64. sql.append(" ORDER BY `id` DESC");
  65.  
  66. return sql.toString();
  67. }

在测试类中新增测试方法:

  1. private ArticleCategory articleCategory;
  2. private final String title = "category test title";
  3. private final String titleNew = "category test title new";
  4.  
  5. @Test
  6. public void testGetById() {
  7. ArticleCategory articleCategory = this.articleCategoryMapper.getById(this.articleCategory.getId());
  8. Assert.assertEquals(articleCategory.getId(), this.articleCategory.getId());
  9. Assert.assertEquals(articleCategory.getTitle(), this.title);
  10. }
  11.  
  12. @Test
  13. public void testGetByIds() {
  14. List<Integer> idList = new ArrayList<Integer>(Arrays.asList(5, 6));
  15. List<ArticleCategory> queryList = this.articleCategoryMapper.getByIds(idList);
  16. Assert.assertEquals(queryList.size(), idList.size());
  17. }
  18.  
  19. @Test
  20. public void testGetIdsByCondition() {
  21. ArticleCategory articleCategory = new ArticleCategory();
  22. articleCategory.setState(DataStatus.Living);
  23. articleCategory.setTitle("test");
  24.  
  25. List<Integer> idList = this.articleCategoryMapper.getIdsByCondition(articleCategory);
  26. Assert.assertTrue(idList.isEmpty() == false);
  27. }
  28.  
  29. @Test
  30. public void testGetLivingIds() {
  31. List<ArticleCategory> articleCategoryList=this.articleCategoryMapper.queryListByState(DataStatus.Living);
  32. Assert.assertTrue(articleCategoryList.isEmpty() == false);
  33. }
  34.  
  35. @Test
  36. public void testQueryList() {
  37. ArticleCategory queryArticleCategory = new ArticleCategory();
  38. queryArticleCategory.setTitle("test");
  39.  
  40. List<ArticleCategory> queryResultList = this.articleCategoryMapper.queryList(queryArticleCategory);
  41. Assert.assertFalse(queryResultList.size() == 0);
  42. }

map测试代码:

  1. @Test
  2. public void testGetIdVsModelMap() {
  3. Map<Integer,ArticleCategory> queryItems=this.articleCategoryMapper.getIdVsModelMap(DataStatus.Living);
  4. Assert.assertTrue(queryItems.size()>0);
  5. }
  6.  
  7. @Autowired
  8. private SqlSessionFactory sqlSessionFactory;
  9.  
  10. @Test
  11. public void testGetIdVsTitleMap() {
  12. MapResultHandler mapResultHandler=new MapResultHandler();
  13. this.sqlSessionFactory.openSession().select("com.dx.test.mapper.ArticleCategoryMapper.getIdVsTitleMap", DataStatus.Living,mapResultHandler);
  14. @SuppressWarnings("unchecked")
  15. Map<Integer, String> queryMap=mapResultHandler.getMappedResults();
  16.  
  17. Assert.assertTrue(queryMap.size()>0);
  18. }
  19.  
  20. @Test
  21. public void testGetIdVsTitleMapWithResultHandler() {
  22. MapResultHandler mapResultHandler=new MapResultHandler();
  23. this.articleCategoryMapper.getIdVsTitleMapWithResultHandler(DataStatus.Living, mapResultHandler);
  24. Assert.assertTrue(mapResultHandler.getMappedResults().size()>0);
  25. }

注意:上边返回map的用法中,如果是非Map<Integer,Model>的模式时,需要使用ResultHandler来辅助实现:

  1. package com.dx.test.mapper.resulthandlers;
  2.  
  3. import java.util.HashMap;
  4. import java.util.Map;
  5.  
  6. import org.apache.ibatis.session.ResultContext;
  7. import org.apache.ibatis.session.ResultHandler;
  8.  
  9. public class MapResultHandler implements ResultHandler {
  10. private final Map mappedResults = new HashMap();
  11.  
  12. @Override
  13. public void handleResult(ResultContext context) {
  14. @SuppressWarnings("rawtypes")
  15. Map map = (Map) context.getResultObject();
  16. mappedResults.put(map.get("key"), map.get("value"));
  17. }
  18.  
  19. public Map getMappedResults() {
  20. return mappedResults;
  21. }
  22. }

3)新增、批量新增

在mapper类中新建查询、批量查询接口:

  1. /**
  2. * +入库文章分类
  3. *
  4. * @param articleCategory 待入库实体
  5. * @return 影响条数
  6. */
  7. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE, useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
  8. @InsertProvider(type = ArticleCategorySqlProvider.class, method = "insert")
  9. int insert(ArticleCategory articleCategory);
  10. /**
  11. * +批量添加记录
  12. *
  13. * @param articleCategoryList 文章分类列表
  14. * @return returnResult
  15. */
  16. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE, useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
  17. @InsertProvider(type = ArticleCategorySqlProvider.class, method = "batchInsert")
  18. int batchInserts(@Param("list") final List<ArticleCategory> articleCategoryList);
  19.  
  20. /**
  21. * +批量添加记录
  22. *
  23. * @param articleCategoryList 文章分类列表
  24. * @return returnResult
  25. */
  26. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE, useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
  27. @Insert(value = "<script>"
  28. + "INSERT INTO `article_category`"
  29. + "(`title`,`img_src`,`description`,`state`,`create_time`,`create_user`,`create_user_id`,`update_time`,`update_user`,`update_user_id`,`version`)"
  30. + "VALUES"
  31. + "<foreach collection=\"list\" item=\"item\" index=\"index\" separator=\",\">"
  32. + " (#{item.title},#{item.imgSrc},#{item.description},#{item.state},now(),#{item.createUser},#{item.createUserId},now(),#{item.updateUser},#{item.updateUserId},0)"
  33. + "</foreach>"
  34. + "ON DUPLICATE KEY UPDATE `update_time` = now()"
  35. + "</script>")
  36. int batchInsertsWithScript(@Param("list") final List<ArticleCategory> articleCategoryList);

在mapper sql provider类中新建sql帮助方法:

  1. /**
  2. * 生成插入文章分类的SQL
  3. *
  4. * @param articleCategory文章分类
  5. * @return 返回插入文章SQL
  6. */
  7. public String insert(ArticleCategory articleCategory) {
  8. return new SQL() {
  9. {
  10. INSERT_INTO("article_category");
  11. INTO_COLUMNS("title", "img_src", "description","state", "create_user", "create_user_id", "create_time","update_user", "update_user_id", "update_time", "version");
  12. INTO_VALUES("#{title}", "#{imgSrc}", "#{description}", "#{state}", "#{createUser}", "#{createUserId}", "now()","#{updateUser}", "#{updateUserId}", "now()", "0");
  13. }
  14. }.toString();
  15. }
  16.  
  17. /**
  18. * 生成批量新增SQL
  19. *
  20. * @param map 参数信息
  21. * @return 生成批量插入SQL语句
  22. * */
  23. public String batchInsert(Map<String, List<ArticleCategory>> map) {
  24. List<ArticleCategory> tmpList = map.get("list");
  25. if (tmpList == null || tmpList.isEmpty()) {
  26. return null;
  27. }
  28.  
  29. StringBuilder sql = new StringBuilder("");
  30. sql.append("INSERT INTO `article_category`");
  31. sql.append("(`title`,`img_src`,`description`,`state`,`create_time`,`create_user`,`create_user_id`,`update_time`,`update_user`,`update_user_id`,`version`)");
  32. sql.append("VALUES");
  33. for (int i = 0; i < tmpList.size(); i++) {
  34. sql.append("(#{list[" + i + "].title},#{list[" + i + "].imgSrc},#{list[" + i + "].description},#{list["+i+"].state},now(),#{list[" + i + "].createUser},#{list[" + i + "].createUserId},now(),#{list[" + i + "].updateUser},#{list[" + i + "].updateUserId},0),");
  35. }
  36. sql.deleteCharAt(sql.length() - 1);
  37. sql.append(" ON DUPLICATE KEY UPDATE `update_time` = now()");
  38. sql.append(";");
  39.  
  40. return sql.toString();
  41. }

在测试类中新增测试方法:

  1. @Test
  2. public void testInsert() {
  3. ArticleCategory articleCategory = new ArticleCategory();
  4. articleCategory.setTitle(title);
  5. articleCategory.setDescription("category description");
  6. articleCategory.setImgSrc("http://www.test.com/img/category/img-" + new Random().nextInt(1000) + ".gif");
  7. articleCategory.setState(DataStatus.Living);
  8. articleCategory.setCreateTime(new Date());
  9. articleCategory.setCreateUser("create user");
  10. articleCategory.setCreateUserId("user-" + new Random().nextInt(1000));
  11.  
  12. int result = this.articleCategoryMapper.insert(articleCategory);
  13. this.articleCategory = articleCategory;
  14. Assert.assertEquals(result, 1);
  15. }
  16.  
  17. @Test
  18. public void testBatchInsert() {
  19. List<ArticleCategory> articleCategoryList = new ArrayList<ArticleCategory>();
  20. for (int i = 0; i < 10; i++) {
  21. ArticleCategory articleCategory = new ArticleCategory();
  22. articleCategory.setTitle(title + i);
  23. articleCategory.setState(DataStatus.Living);
  24. articleCategory.setDescription("category description");
  25. articleCategory.setImgSrc("http://www.test.com/img/category/img-" + new Random().nextInt(1000) + ".gif");
  26. articleCategory.setCreateTime(new Date());
  27. articleCategory.setCreateUser("create user");
  28. articleCategory.setCreateUserId("user-" + new Random().nextInt(1000));
  29.  
  30. articleCategoryList.add(articleCategory);
  31. }
  32.  
  33. int result = this.articleCategoryMapper.batchInserts(articleCategoryList);
  34. Assert.assertEquals(result, 10);
  35. }
  36.  
  37. @Test
  38. public void testBatchInsertWithScript() {
  39. List<ArticleCategory> articleCategoryList = new ArrayList<ArticleCategory>();
  40. for (int i = 0; i < 10; i++) {
  41. ArticleCategory articleCategory = new ArticleCategory();
  42. articleCategory.setTitle(title + i);
  43. articleCategory.setState(DataStatus.Living);
  44. articleCategory.setDescription("category description");
  45. articleCategory.setImgSrc("http://www.test.com/img/category/img-" + new Random().nextInt(1000) + ".gif");
  46. articleCategory.setCreateTime(new Date());
  47. articleCategory.setCreateUser("create user");
  48. articleCategory.setCreateUserId("user-" + new Random().nextInt(1000));
  49.  
  50. articleCategoryList.add(articleCategory);
  51. }
  52.  
  53. int result = this.articleCategoryMapper.batchInsertsWithScript(articleCategoryList);
  54. Assert.assertEquals(result, 10);
  55. }

4)修改、批量修改

在mapper类中新建查询、批量查询接口:

  1. /**
  2. * +根据文章id,删除文章
  3. *
  4. * @param id 文章id
  5. * @return 影响条数
  6. */
  7. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
  8. @UpdateProvider(type = ArticleCategorySqlProvider.class, method = "update")
  9. int update(ArticleCategory articleCategory);
  10.  
  11. /**
  12. * +批量新增
  13. * @param articleCategoryList 待修改对象
  14. * @return 影响条数
  15. * */
  16. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
  17. @UpdateProvider(type = ArticleCategorySqlProvider.class, method = "batchUpdate")
  18. int batchUpdate(List<ArticleCategory> articleCategoryList);
  19.  
  20. /**
  21. * +批量新增
  22. * @param articleCategoryList 待修改对象
  23. * @return 影响条数
  24. * */
  25. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
  26. @Update(value="<script>"
  27. + "<foreach item=\"item\" collection=\"list\" open=\"\" separator=\";\" close=\"\">"
  28. + "update `article_category` "
  29. + "<set>" +
  30. " `id`=#{item.id} "
  31. + " <if test='item.title !=null and item.title != \"\"'>" +
  32. " ,`title` = #{item.title} " +
  33. " </if> " +
  34. " <if test='item.imgSrc !=null'>" +
  35. " ,`img_src` = #{item.imgSrc} " +
  36. " </if> " +
  37. " <if test='item.description !=null and item.description != \"\"'>" +
  38. " ,`description` = #{item.description} " +
  39. " </if> " +
  40. " <if test='item.state !=null'>" +
  41. " ,`state` = #{item.state} " +
  42. " </if> " +
  43. ",`update_time` = now(), `update_user` = #{item.updateUser}, `update_user_id` = #{item.updateUserId}, `version` = `version` + 1 "
  44. + "</set>"
  45. + "where `id` = #{item.id} and `version`=#{item.version}"
  46. + "</foreach>"
  47. + "</script>")
  48. int batchUpdateWithScript(List<ArticleCategory> articleCategoryList);

在mapper sql provider类中新建sql帮助方法:

  1. /**
  2. * 生成修改文章分类SQL
  3. *
  4. * @param articleCategory 文章分类实体
  5. * @return 返回修改文章分类SQL
  6. */
  7. public String update(ArticleCategory articleCategory) {
  8. StringBuilder sql = new StringBuilder();
  9.  
  10. sql.append("update `article_category` set id=#{id}");
  11. if (articleCategory.getTitle() != null) {
  12. sql.append(", `title`=#{title}");
  13. }
  14. if (articleCategory.getImgSrc() != null) {
  15. sql.append(", `img_src`=#{imgSrc}");
  16. }
  17. if (articleCategory.getDescription() != null) {
  18. sql.append(", `description`=#{description}");
  19. }
  20. if(articleCategory.getState()!=null) {
  21. sql.append(", `state` = #{state}");
  22. }
  23. if (articleCategory.getCreateUser() != null) {
  24. sql.append(", `create_user` = #{createUser}");
  25. }
  26. if (articleCategory.getCreateUserId() != null) {
  27. sql.append(", `create_user_id` = #{createUserId}");
  28. }
  29. sql.append(", `update_time` = now()");
  30. if (articleCategory.getUpdateUser() != null) {
  31. sql.append(", `update_user` = #{updateUser}");
  32. }
  33. if (articleCategory.getUpdateUserId() != null) {
  34. sql.append(", `update_user_id` = #{updateUserId}");
  35. }
  36.  
  37. sql.append(", `version` = `version` + 1");
  38. sql.append(" WHERE `id` = #{id} AND `version` = #{version}");
  39.  
  40. return sql.toString();
  41. }
  42.  
  43. /**
  44. * 生成批量更新SQL
  45. *
  46. * @param map 查询参数
  47. * @return 返回生成的批量更新语句
  48. * */
  49. public String batchUpdate(Map<String, List<ArticleCategory>> map) {
  50. List<ArticleCategory> tmpList = map.get("list");
  51. if (tmpList == null || tmpList.isEmpty()) {
  52. return null;
  53. }
  54.  
  55. StringBuilder sql = new StringBuilder("");
  56.  
  57. for (int i = 0; i < tmpList.size(); i++) {
  58. ArticleCategory articleCategory=tmpList.get(i);
  59. sql.append("update `article_category` set id=#{list["+i+"].id}");
  60. if (articleCategory.getTitle() != null) {
  61. sql.append(", `title`=#{list["+i+"].title}");
  62. }
  63. if (articleCategory.getImgSrc() != null) {
  64. sql.append(", `img_src`=#{list["+i+"].imgSrc}");
  65. }
  66. if (articleCategory.getDescription() != null) {
  67. sql.append(", `description`=#{list["+i+"].description}");
  68. }
  69. if(articleCategory.getState()!=null) {
  70. sql.append(", `state` = #{list["+i+"].state}");
  71. }
  72. if (articleCategory.getCreateUser() != null) {
  73. sql.append(", `create_user` = #{list["+i+"].createUser}");
  74. }
  75. if (articleCategory.getCreateUserId() != null) {
  76. sql.append(", `create_user_id` = #{list["+i+"].createUserId}");
  77. }
  78. sql.append(", `update_time` = now()");
  79. if (articleCategory.getUpdateUser() != null) {
  80. sql.append(", `update_user` = #{list["+i+"].updateUser}");
  81. }
  82. if (articleCategory.getUpdateUserId() != null) {
  83. sql.append(", `update_user_id` = #{list["+i+"].updateUserId}");
  84. }
  85.  
  86. sql.append(", `version` = `version` + 1");
  87. sql.append(" WHERE `id` = #{list["+i+"].id} AND `version` = #{list["+i+"].version}");
  88. sql.append(";");
  89. }
  90.  
  91. return sql.toString();
  92. }

在测试类中新增测试方法:

  1. @Test
  2. public void testUpdate() {
  3. ArticleCategory articleCategory = this.articleCategoryMapper.getById(this.articleCategory.getId());
  4. Assert.assertEquals(articleCategory.getId(), this.articleCategory.getId());
  5. Assert.assertEquals(articleCategory.getTitle(), this.title);
  6.  
  7. articleCategory.setTitle(this.titleNew);
  8. int result = this.articleCategoryMapper.update(articleCategory);
  9. Assert.assertEquals(result, 1);
  10.  
  11. articleCategory = this.articleCategoryMapper.getById(this.articleCategory.getId());
  12. Assert.assertEquals(articleCategory.getId(), this.articleCategory.getId());
  13. Assert.assertEquals(articleCategory.getTitle(), this.title);
  14. }
  15.  
  16. @Test
  17. public void testBatchUpdate() {
  18. ArticleCategory queryArticleCategory = new ArticleCategory();
  19. queryArticleCategory.setTitle("ccccc");
  20. List<ArticleCategory> queryItems = this.articleCategoryMapper.queryList(queryArticleCategory);
  21. for (ArticleCategory articleCategory : queryItems) {
  22. articleCategory.setTitle("DDD");
  23. }
  24.  
  25. int result = this.articleCategoryMapper.batchUpdate(queryItems);
  26. Assert.assertEquals(result, 1);
  27. }
  28.  
  29. @Test
  30. public void testBatchUpdateWithScript() {
  31. ArticleCategory queryArticleCategory = new ArticleCategory();
  32. queryArticleCategory.setTitle("DDD");
  33. List<ArticleCategory> queryItems = this.articleCategoryMapper.queryList(queryArticleCategory);
  34. for (ArticleCategory articleCategory : queryItems) {
  35. articleCategory.setTitle("ccccc");
  36. }
  37.  
  38. int result = this.articleCategoryMapper.batchUpdateWithScript(queryItems);
  39. Assert.assertEquals(result, 1);
  40. }

测试执行批量插入,按照上边jdbc.properties和spring-config.xml配置中会抛出以下异常:

  1. Caused by: java.sql.SQLException: sql injection violation, multi-statement not allow : update `article_category` set id=?, `title`=?, `img_src`=?, `description`=?, `state` = ?, `create_user` = ?, `create_user_id` = ?, `update_time` = now(), `version` = `version` + 1 WHERE `id` = ? AND `version` = ?;update `article_category` set id=?, `title`=?, `img_src`=?, `description`=?, `state` = ?, `create_user` = ?, `create_user_id` = ?, `update_time` = now(), `version` = `version` + 1 WHERE `id` = ? AND `version` = ?;update `article_category` set id=?, `title`=?, `img_src`=?, `description`=?, `state` = ?, `create_user` = ?, `create_user_id` = ?, `update_time` = now(), `version` = `version` + 1 WHERE `id` = ? AND `version` = ?;update `article_category` set id=?, `title`=?, `img_src`=?, `description`=?, `state` = ?, `create_user` = ?, `create_user_id` = ?, `update_time` = now(), `version` = `version` + 1 WHERE `id` = ? AND `version` = ?;
  2. at com.alibaba.druid.wall.WallFilter.checkInternal(WallFilter.java:808)
  3. at com.alibaba.druid.wall.WallFilter.connection_prepareStatement(WallFilter.java:294)
  4. at com.alibaba.druid.filter.FilterChainImpl.connection_prepareStatement(FilterChainImpl.java:610)
  5. at com.alibaba.druid.filter.FilterAdapter.connection_prepareStatement(FilterAdapter.java:943)
  6. at com.alibaba.druid.filter.FilterEventAdapter.connection_prepareStatement(FilterEventAdapter.java:143)
  7. at com.alibaba.druid.filter.FilterChainImpl.connection_prepareStatement(FilterChainImpl.java:610)
  8. at com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.prepareStatement(ConnectionProxyImpl.java:374)
  9. at com.alibaba.druid.pool.DruidPooledConnection.prepareStatement(DruidPooledConnection.java:388)
  10. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  11. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  12. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  13. at java.lang.reflect.Method.invoke(Method.java:498)
  14. at org.apache.ibatis.logging.jdbc.ConnectionLogger.invoke(ConnectionLogger.java:55)
  15. at com.sun.proxy.$Proxy38.prepareStatement(Unknown Source)
  16. at org.apache.ibatis.executor.statement.PreparedStatementHandler.instantiateStatement(PreparedStatementHandler.java:85)
  17. at org.apache.ibatis.executor.statement.BaseStatementHandler.prepare(BaseStatementHandler.java:88)
  18. at org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare(RoutingStatementHandler.java:59)
  19. at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:85)
  20. at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:49)
  21. at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
  22. at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
  23. at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
  24. at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  25. at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  26. at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  27. at java.lang.reflect.Method.invoke(Method.java:498)
  28. at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:426)
  29. ... 37 more

此时出现错误原因,多个sql语句执行被过滤器过滤掉了。

问题解决:

1)需要在jdbc.properties中url中添加allowMultiQueries=true

  1. #jdbc settings
  2. jdbc.driver=com.mysql.cj.jdbc.Driver
  3. jdbc.url=jdbc:mysql://localhost:3306/mydb?allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
  4. jdbc.username=root
  5. jdbc.password=123456
  6.  
  7. #pool settings
  8. jdbc.pool.init=1
  9. jdbc.pool.minIdle=3
  10. jdbc.pool.maxActive=20
  11.  
  12. #jdbc.testSql=SELECT 'x'
  13. jdbc.testSql=SELECT 'x' FROM DUAL

2)在spring-config.xml中修改,添加wall-filter/stat-filter,并引入dataSource下。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context-4.0.xsd ">
  9.  
  10. <!-- bean annotation driven -->
  11. <context:annotation-config />
  12. <context:component-scan base-package="com.dx.test.repository,com.dx.test.mapper,com.dx.test.service" />
  13.  
  14. <!-- 配置整合Mybatis过程 -->
  15. <!-- 配置数据库相关参数 properties的属性:${url} -->
  16. <context:property-placeholder location="classpath:jdbc.properties" />
  17. <!--
  18. <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  19. <property name="locations">
  20. <list>
  21. <value>classpath:jdbc.properties</value>
  22. </list>
  23. </property>
  24. </bean>
  25. -->
  26.  
  27. <!--2.配置连接池属性 -->
  28. <!-- 数据源配置, 使用 Druid 数据库连接池 -->
  29. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
  30. <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
  31. <property name="driverClassName" value="${jdbc.driver}" />
  32.  
  33. <!-- 基本属性 url、user、password -->
  34. <property name="url" value="${jdbc.url}" />
  35. <property name="username" value="${jdbc.username}" />
  36. <property name="password" value="${jdbc.password}" />
  37.  
  38. <!-- 配置初始化大小、最小、最大 -->
  39. <property name="initialSize" value="${jdbc.pool.init}" />
  40. <property name="minIdle" value="${jdbc.pool.minIdle}" />
  41. <property name="maxActive" value="${jdbc.pool.maxActive}" />
  42.  
  43. <!-- 配置获取连接等待超时的时间 -->
  44. <property name="maxWait" value="60000" />
  45.  
  46. <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
  47. <property name="timeBetweenEvictionRunsMillis" value="60000" />
  48.  
  49. <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
  50. <property name="minEvictableIdleTimeMillis" value="300000" />
  51.  
  52. <property name="validationQuery" value="${jdbc.testSql}" />
  53. <property name="testWhileIdle" value="true" />
  54. <property name="testOnBorrow" value="false" />
  55. <property name="testOnReturn" value="false" />
  56. <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) -->
  57. <!-- <property name="poolPreparedStatements" value="true"/> <property name="maxPoolPreparedStatementPerConnectionSize"
  58. value="20"/> -->
  59. <property name="proxyFilters">
  60. <list>
  61. <ref bean="stat-filter" />
  62. <ref bean="wall-filter" />
  63. </list>
  64. </property>
  65. <!-- 配置监控统计拦截的filters: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall -->
  66. <property name="filters" value="stat,wall" />
  67. </bean>
  68. <bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter">
  69. <property name="slowSqlMillis" value="30000" />
  70. <property name="logSlowSql" value="true" />
  71. <property name="mergeSql" value="true" />
  72. </bean>
  73. <bean id="wall-filter" class="com.alibaba.druid.wall.WallFilter">
  74. <property name="dbType" value="mysql" />
  75. <property name="config" ref="wall-config" />
  76. </bean>
  77. <bean id="wall-config" class="com.alibaba.druid.wall.WallConfig">
  78. <!-- 批量sql -->
  79. <property name="multiStatementAllow" value="true" />
  80. </bean>
  81.  
  82. <!--3.配置SqlSessionFactory对象 -->
  83. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  84. <!--注入数据库连接池 -->
  85. <property name="dataSource" ref="dataSource" />
  86. <!--配置mybatis全局配置文件:mybatis-config.xml -->
  87. <property name="configLocation"
  88. value="classpath:mybatis-config.xml" />
  89. <!-- 因为我们这采用的是Mybatis Java API方式,因此不需要配置 -->
  90. <!--扫描entity包,使用别名,多个用;隔开 -->
  91. <!-- <property name="typeAliasesPackage" value="com.dx.test.model"/> -->
  92. <!--扫描sql配置文件:mapper需要的xml文件 -->
  93. <!-- <property name="mapperLocations" value="classpath:mapper/*.xml"/> -->
  94. </bean>
  95.  
  96. <!-- Mapper接口所在包名,Spring会自动查找其下的类 -->
  97. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  98. <property name="basePackage" value="com.dx.test.mapper" />
  99. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
  100. </bean>
  101.  
  102. <!-- 如果想对单个mapper类关联上sqlSessionFactory,可以这么使用,具体参考:http://mybatis.org/spring/getting-started.html -->
  103. <!-- <bean id="articlerMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  104. <property name="mapperInterface" value="com.dx.test.dao.mapper.ArticleMapper"
  105. /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean> -->
  106.  
  107. <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
  108. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  109. <property name="dataSource" ref="dataSource" />
  110. </bean>
  111. </beans>

上边加粗本分是要修改的部分。

5)删除、批量删除

在mapper类中新建查询、批量查询接口:

  1. /**
  2. * +根据文章分类id,删除文章分类
  3. *
  4. * @param id 文章分类id
  5. * @return 影响条数
  6. */
  7. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
  8. @Delete("delete from article_category where id=#{id}")
  9. int delete(Integer id);
  10.  
  11. /**
  12. * +根据文章分类id集合,删除文章分类
  13. *
  14. * @param list 文章分类id集合
  15. * @return 影响条数
  16. */
  17. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
  18. @DeleteProvider(type = ArticleCategorySqlProvider.class, method = "batchDelete")
  19. int batchDelete(@Param("list") List<Integer> list);
  20.  
  21. /**
  22. * +批量删除记录
  23. *
  24. * @param list 待删除id集合
  25. * @return returnResult
  26. */
  27. @Options(useCache = true, flushCache = Options.FlushCachePolicy.TRUE)
  28. @Delete("<script>" +
  29. "delete from `article_category` where `id` in " +
  30. "<foreach collection=\"list\" index=\"i\" open=\"(\" separator=\",\" close=\")\" item=\"item\" >" +
  31. "#{item}" +
  32. "</foreach>" +
  33. "</script>")
  34. int batchDeleteWithScript(@Param("list") List<Integer> list);

在mapper sql provider类中新建sql帮助方法:

  1. /**
  2. * +根据id集合,获取文章分类列表 SQL
  3. *
  4. * @param map map
  5. * @return returnResult
  6. */
  7. public String batchDelete(final Map<String, List<Integer>> map) {
  8. List<Integer> tmpList = map.get("list");
  9. if (tmpList == null || tmpList.isEmpty()) {
  10. return null;
  11. }
  12.  
  13. StringBuilder sql = new StringBuilder("DELETE FROM `article_category` WHERE `id` in (");
  14. for (int i = 0; i < tmpList.size(); i++) {
  15. sql.append("#{list[" + i + "]},");
  16. }
  17. sql.deleteCharAt(sql.length() - 1);
  18. sql.append(")");
  19. sql.append(";");
  20.  
  21. return sql.toString();
  22. }

在测试类中新增测试方法:

  1. @Test
  2. public void testDelete() {
  3. int result = this.articleCategoryMapper.delete(this.articleCategory.getId());
  4. Assert.assertEquals(result, 1);
  5. }
  6.  
  7. @Test
  8. public void testBatchDelete() {
  9. List<Integer> idList = new ArrayList<Integer>(Arrays.asList(1, 2));
  10. int result = this.articleCategoryMapper.batchDelete(idList);
  11. Assert.assertEquals(result, idList.size());
  12. }
  13.  
  14. @Test
  15. public void testBatchDeleteWithScript() {
  16. List<Integer> idList = new ArrayList<Integer>(Arrays.asList(3, 4));
  17. int result = this.articleCategoryMapper.batchDeleteWithScript(idList);
  18. Assert.assertEquals(result, idList.size());
  19. }

参考《MyBatis与Druid数据库连接池集成监控统计后WallFilterSQL注入异常问题处理方案


MyBatis(九):Mybatis Java API批量操作(增、删、改、查)的更多相关文章

  1. 好用的SQL TVP~~独家赠送[增-删-改-查]的例子

    以前总是追求新东西,发现基础才是最重要的,今年主要的目标是精通SQL查询和SQL性能优化.  本系列主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础] ...

  2. iOS FMDB的使用(增,删,改,查,sqlite存取图片)

    iOS FMDB的使用(增,删,改,查,sqlite存取图片) 在上一篇博客我对sqlite的基本使用进行了详细介绍... 但是在实际开发中原生使用的频率是很少的... 这篇博客我将会较全面的介绍FM ...

  3. iOS sqlite3 的基本使用(增 删 改 查)

    iOS sqlite3 的基本使用(增 删 改 查) 这篇博客不会讲述太多sql语言,目的重在实现sqlite3的一些基本操作. 例:增 删 改 查 如果想了解更多的sql语言可以利用强大的互联网. ...

  4. django ajax增 删 改 查

    具于django ajax实现增 删 改 查功能 代码示例: 代码: urls.py from django.conf.urls import url from django.contrib impo ...

  5. ADO.NET 增 删 改 查

    ADO.NET:(数据访问技术)就是将C#和MSSQL连接起来的一个纽带 可以通过ADO.NET将内存中的临时数据写入到数据库中 也可以将数据库中的数据提取到内存中供程序调用 ADO.NET所有数据访 ...

  6. MVC EF 增 删 改 查

    using System;using System.Collections.Generic;using System.Linq;using System.Web;//using System.Data ...

  7. python基础中的四大天王-增-删-改-查

    列表-list-[] 输入内存储存容器 发生改变通常直接变化,让我们看看下面列子 增---默认在最后添加 #append()--括号中可以是数字,可以是字符串,可以是元祖,可以是集合,可以是字典 #l ...

  8. MyBatis的配置与使用(增,删,改,查)

    ---恢复内容开始--- Mybatis入门介绍 一.MyBatis介绍 什么是MyBtis? MyBatis 是一个简化和实现了 Java 数据持久化层(persistence layer)的开源框 ...

  9. Java操作MongoDB:连接&增&删&改&查

    1.连接 ①方式一 MongoClientOptions.Builder builder = MongoClientOptions.builder(); //可以通过builder做各种详细配置 Mo ...

  10. js数组的管理[增,删,改,查]

    今天在设计表单的时候遇到对数组的一些处理的问题,比如说怎么创建一个数组,然后牵扯到数组的增删改查的方法.请看API FF: Firefox, N: Netscape, IE: Internet Exp ...

随机推荐

  1. python递归函数的执行过程

    举例: def nove(n,a,b,c): if n == 1: print(a,'------------>',c) else: nove(n-1,a,c,b) nove(1,a,b,c) ...

  2. Objective-C之深浅拷贝

    深拷贝(指针和指向都改变) , 浅拷贝(指针改变,指向不变) NSString *s1 = @"string"; NSLog(@"s1 : %p, %p, %@" ...

  3. APP开发基础知识(转载)

    来源:https://www.cnblogs.com/wangsea/p/9413672.html 本文针对小白用户对App做一个简单的介绍,首先要了解App都有哪些类型,不同的类型适用于哪些需求,用 ...

  4. AR自动开票主程序导入发票的时候,出现错误提示''不能获取汇款地址''

    问题:AR自动开票主程序,出现错误不能获取汇款地址 解决:AR>设置-打印-汇入地址,汇入地址要增加此客户地点对应的国家:

  5. day 39

    ORM 对象关系映射 表 ---> 类 字段 ---> 属性 记录 ---> 对象 优点: ​ 使用者无需关心具体的SQL命令如何编写. ​ 直接通过调用方法,来执行相对应的SQL命 ...

  6. 利用Metasploit攻击Android

    首先我在Kali下生成一个Android的应用程序,即apk格式的文件,用到的命令是: msfvenom -p android/meterpreter/reverse_tcp LHOST=本地ip L ...

  7. C++学习(9)—— 对象的初始化及清理

    1. 构造函数和析构函数 对象的初始化和清理是两个非常重要的安全问题 ​ 一个对象或者变量没有初始状态,对其使用后果是未知 ​ 同样的使用完一个对象或者变量,没有及时清理,也会造成一些安全问题   C ...

  8. Git for Windows安装教程

    1.国内直接从官网(http://git-scm.com/download/win)下载比较困难,速度极慢,需要翻墙. 这里提供一个国内的下载站,方便网友下载(https://npm.taobao.o ...

  9. 开发基础之牛逼哄哄的 Lambda 表达式,简洁优雅就是生产力

    什么是Lambda? 我们知道,对于一个Java变量,我们可以赋给其一个“值”. 如果你想把“一块代码”赋给一个Java变量,应该怎么做呢? 比如,我想把右边那块代码,赋给一个叫做aBlockOfCo ...

  10. No root/virtual joint specified in SRDF. Assuming fixed joint

    在用MoveIt!配置文件时,加载urdf模型时,显示Success......但没有显示模型,终端显示错误如下: 增加虚拟关节就好.