MyBatis 学习(二)
一、解决字段名与属性名不一致
1、数据库字段与属性名不一致
-
public class User { // 测试当数据库的字段与对应的属性不一致是 private int id; private String name; private int pwd; .... }
<!--通过id查询用户--> <select id="getUserById" parameterType="int" resultType="com.study.pojo.User" > select * from mybatis.user where id = #{id} </select>
出现问题:
-
User{id=1, name='null', pwd=0}
Process finished with exit code 0
解决:
-
方式1:sql起别名(不可取)
<!--解决方式1;起别名--> <select id="getUserById" parameterType="int" resultType="com.study.pojo.User" > select id,username as name,password as pwd from mybatis.user where id = #{id} </select>
-
方式二:使用resultMap 结果集映射:
resultMap
元素是 MyBatis 中最重要最强大的元素
2、resultMap 结果集映射
-
数据库:id,username,password
User类:id,name,pwd
-
使用resultMap(形成数据库字段名与实体类属性名映射关系)
<resultMap id="UserMap" type="user"> <!--column:数据库的字段名 property:实体类的属性名--> <result column="username" property="name"/> <result column="password" property="pwd"/> </resultMap> <select id="getUserById" parameterType="int" resultMap="UserMap" > select * from mybatis.user where id = #{id} </select>
User{id=1, name='yyb', pwd=123467}
Process finished with exit code 0
-
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
-
实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份
resultMap
能够代替实现同等功能的数千行代码。 -
ResultMap
的优秀之处——你完全可以不用显式地配置它们。
二、日志
1、日志工厂
-
如果一个数据操作执行sql是出现问题,我们需要排错,日志就是最好的助手!
-
之前:输出 dug
-
现在:日志工厂!
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设置 -
SLF4J |【掌握】
-
LOG4J
-
LOG4J2
-
JDK_LOGGING
-
COMMONS_LOGGING
-
STDOUT_LOGGING 【掌握】
-
NO_LOGGING
在mybits中具体使用那个日志实现,在设置中设定!
- STDOUT_LOGGING 标准输出(默认)
- 在mybatis核心配置文件中设置
<!--标准的日志实现--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings>
输出:
Opening JDBC Connection
Created connection 1166151249.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@45820e51]
== > Preparing: select * from mybatis.user where id = ?
== Parameters: 1(Integer)
== Columns: id, username, password
== Row: 1, yyb, 123467
== Total: 1
User{id=1, name='yyb', pwd=123467}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@45820e51]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@45820e51]
Returned connection 1166151249 to pool.Process finished with exit code 0
2、Log4j
-
是什么是log4j
-
如何使用log4j
-
1、导入log4j的依赖jar。如果使用maven项目,也可以选择在pom.xml中新增依赖:
<!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency>
- 2、配置log4j(通用版)。在src/main/resources/db.properties创建
log4j.rootLogger=DEBUG,console,file #控制台输出的相关设置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=【%c】-%m%n #文件输出的相关设置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File=./log/yyb.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold=DEBUG log4j.appender.file.layout=org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern=【%p】【%d{yy-MM-dd}】【%c】%m%n #日志输出级别 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
-
3、配置log4j为日志实现
<!--日志输出--> <settings> <setting name="logImpl" value="LOG4J"/> </settings>
-
4、log的使用,直接测试运行的测试了类
-
1、简单使用:编写log4j的测试类
-
导入的包:import org.apache.log4j.Logger;
-
日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserDaoMapperTest.class);
-
测试输出不同级别:
//Log4j测试 @Test public void testLog4J(){ logger.info("info:进入了log4j方式"); logger.debug("dabug:进入了dabug方式"); logger.error("error:进入了error方式"); }
并在工程目录下自动生成:log日志
三、分页
1、什么是分页
- 将大量数据展示分割成多页显示,减少数据的处理量
2、Sql语法Limit分页
-
SELECT * FROM USER LIMIT startIndex,pageSize; SELECT * FROM USER LIMIT 3 ;#[0,3] limit n 查找前n行记录 limit n,m 从第n行开始,查找m行记录(起始行为第0行)3
3、使用Limit实现分页,核心SQL
-
接口功能Mapper
//通过分页limit查询用户 List<User> getUserByLimit(Map<String,Integer> map);
-
功能实现Mapper.xml
<!--使用limit查询--> <select id="getUserByLimit" parameterType="map" resultMap="UserMap" > select * from mybatis.user limit #{startIndex},#{pageSize} </select>
-
功能测试Test
/*通过limit查询用户信息*/ @Test public void getUserByLimt(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String,Integer> map = new HashMap(); map.put("startIndex",1); map.put("pageSize",3); List<User> userByLimit = mapper.getUserByLimit(map); userByLimit.forEach(user-> System.out.println(user)); sqlSession.close(); }
4、使用RowBounds实现分页(面向对象实现不在对sql操作)
-
//通过分页RowBounds查询用户 List<User> getUserByRowBounds();
-
<!--使用RoeBounds查询--> <select id="getUserByRowBounds" resultMap="UserMap" > select * from mybatis.user </select>
-
/*通过RowBounds查询用户信息*/ @Test public void getUserByRowBounds() { SqlSession sqlSession = MyBatisUtils.getSqlSession(); //不在使用SQL RowBounds rowBounds = new RowBounds(1,3); //通过代码层面实现分页 List<User> users = sqlSession.selectList("com.study.dao.UserMapper.getUserByRowBounds",null,rowBounds); users.forEach(user-> System.out.println(user)); sqlSession.close(); }
四、使用注解开发
4、1面向接口编程
- 接口本质是一种规范和约束,反映了系统设计者对系统的抽象理解。换一种说法,面向接口编程,写业务的不需要遵守。当设计和实现分离的时候,面向接口编程是一种解决问题的很好方式,但是当设计和分离是一个人的时候,就显得非常没有必要。
- 在web开发的工作,mvc也是比较常用的开发模式,这种开发模式通常将代码分成三层(控制层、业务逻辑层、数据库访问层),无论是较早的SSH、SSM、还是现在比较流行的spring boot框架,都提倡面向接口编程,这样可以降低层与层之间的耦合。
4、2 使用注解简单操作
-
它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。
-
/*4、功能接口*/ public interface UserMapper { @Select("select * from mybatis.user") List<User> getUserInfo(); }
-
核心配置文件中:
<mappers> <!--使用注解开发绑定接口--> <mapper class="com.study.dao.UserMapper"/> </mappers>
-
测试
public class UserTest { @Test public void getUserInfo(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> userInfo = mapper.getUserInfo(); userInfo.forEach(user -> System.out.println(user)); sqlSession.close(); } }
-
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
-
比如:在处理数据库字段和对应属性名的问题上不能解决该问题。
4、3 MyBatis详细执行流程
4、4 注解版CRUD
-
在MybatisUtils工具类上自动开启事务提交
public static SqlSession getSqlSession() { /*true:自动提交事务不用手动commit*/ return sqlSessionFactory.openSession(true); }
-
Mapper使用注解CRUD
/*4、功能接口*/ public interface UserMapper { @Select("select * from mybatis.user") List<User> getUserInfo(); //若方法上的有多参数并且类型为基本数据类型和String的必须加上@Param("")注解(与sql的#{}变量是一一对应的) @Select("select * from mybatis.user where id = #{id} or username = #{name}") List<User> getUserByIdOrName(@Param("id") int id,@Param("name") String username); @Insert("insert into user(id,username,password) values(#{id},#{username},#{password})") boolean addUser(User user); @Update("update user set username=#{username},password=#{password} where id =#{id}") boolean updateUser(User user); @Delete("delete from user where id =#{id}") boolean delete(@Param("id") int id); }
-
测试类
public class UserTest { @Test public void getUserByIdOrName(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> users = mapper.getUserByIdOrName(1, "lijing"); users.forEach(user -> System.out.println(user)); sqlSession.close(); ........ }
-
注:若接口方法上的有多参数并且类型为基本数据类型和String的必须加上@Param("")注解(与sql的#{}变量是一一对应的)
引用类型的属性不用此注解
4、5 Lombok
- Lombok项目是一个Java库,它会自动插入您的编辑器和构建工具中,从而使您的Java更加有趣。永远不要再编写另一个getter或equals方法,带有一个注释的类将具有功能齐全的生成器,自动执行日志记录变量等等。
1、使用Lombok
-
1、在IDEA中安装lombok的插件
-
2、在Maven中导入lombok的依赖
<!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> </dependency>
-
3、注解功能
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder,@SuperBuilder,@Singular,@Delegate
@Value
@Accessors
@Wither, @With, @SneakyThrows
@val, @var
experimental @var, @UtilityClass -
@Data:无参构造,getter and setter,toString、hashCode、equals
-
@AllArgsConstructor:有参构造
-
@NoArgsConstructor:无参构造
4、6 多对一处理
- 多对一
- 多个学生,对应一个老师
- 对于学生而言:(关联),多个学生,关联一个老师【多对一】
- 对于老师而言:(集合),一个老师,有很多学生【一对多】
SQL导入:
CREATE TABLE `teacher` ( `id` INT ( 10 ) NOT NULL, `name` VARCHAR ( 30 ) DEFAULT NULL, PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8 INSERT INTO teacher(`id`, `name`) VALUES (1, '王老师'); CREATE TABLE `student` ( `id` INT(10) NOT NULL, `name` VARCHAR(30) DEFAULT NULL, `tid` INT(10) DEFAULT NULL, PRIMARY KEY (`id`), KEY `fktid` (`tid`), CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
测试环境搭建
- 1、在Maven中导入相关依赖,(特别是lombok可以减少代码量(代码生成器))
- 2、在resource下创建mybatis的核心配置文件
- 3、创建mybatis的工具类(创建SqlSessionFactory和SqlSession)
- 4、创建实体类(Student(组合引入Teacher(形成多对一的关系)),Teacher)
- 5、创建Mapper接口(功能方法)
- 6、mybatis的核心配置文件绑定注册Mapper接口或文件(包名)
- 7、在resource下创建同类的包名和相关接口的Mapper.xml
- 8、测试类查询是否成功。
需求:
-
查询所有的学生信息,以及对应老师的的信息。
-
分析:
<!-- 查询所有的学生信息,以及对应老师的的信息。 sql :select s.id,s.name,t.name from student s,teacher t where s.tid=t.id; 1、查询出所有学生的信息 2、根据学生的tid查询出老师的信息 -->
-
解决:
-
方式一:按照查询嵌套处理
-
<select id="getStudent" resultMap="StudentTeacher"> select * from student </select> <resultMap id="StudentTeacher" type="Student"> <result property="id" column="id"/> <result property="name" column="name"/> <!--关联--> <!--复杂的属性,需要单独处理 对象使用:association 集合:collection ;javaType:表字段类型定义为Java的复杂类型--> <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="Teacher"> select * from teacher </select>
-
方式二:按照结果嵌套处理
<!--方式2:按照结果嵌套处理--> <select id="getStudent2" resultMap="StudentTeacher2"> select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid=t.id; </select> <!--property:实体类的属性值;column:数据库的子段值--> <resultMap id="StudentTeacher2" type="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <association property="teacher" javaType="Teacher" > <result property="name" column="tname"/> </association> </resultMap>
-
column | 数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。 |
---|---|
javaType | 一个 Java 类的完全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。 |
select | 用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句 |
resultMap | 结果映射的 ID,可以将嵌套的结果集映射到一个合适的对象树中。 它可以作为使用额外 select 语句的替代方案。它可以将多表连接操作的结果映射成一个单一的 ResultSet 。这样的 ResultSet 将会将包含重复或部分数据重复的结果集。为了将结果集正确地映射到嵌套的对象树中,MyBatis 允许你 “串联”结果映射,以便解决嵌套结果集的问题。 |
4、7 一对多处理
-
eg:一个老师拥有多个学生!
需求:获取指定老师下的学生
-
Student实体类
@Data public class Student { private int id; private String name; private int tid; }
-
Teacher实体类
@Data public class Teacher { private int id; private String name; /*关联一对多关系*/ private List<Student> students; }
-
TeacherMapper接口
public interface TeacherMapper { /*获取指定老师下的学生*/ Teacher getTeacher2(@Param("id") int id); Teacher getTeacher3(@Param("id") int id); }
-
TeacherMapper.xml实现
<!--mapper核心配置文件--> <mapper namespace="com.study.dao.TeacherMapper"> <select id="getTeacher" resultType="Teacher"> select * from teacher; </select> <!--方式一:按照结果嵌套处理--> <select id="getTeacher2" resultMap="TeacherByStudents"> select s.id sid,s.name sname,t.name tname,t.id tid from student s,teacher t where s.tid=t.id and t.id=#{id} ; </select> <resultMap id="TeacherByStudents" type="Teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/> <!--处理复杂类型是集合类型是使用collection javaType:指定属性的类型(eg:Student student) ofType:指定集合中的泛型信息,使用ofType获取 --> <collection property="students" ofType="Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap> <!--方式二:按照结果嵌套处理--> <select id="getTeacher3" resultMap="TeacherByStudents3" > select * from teacher where id =#{id} </select> <resultMap id="TeacherByStudents3" type="Teacher" > <!--column="id":老师的id--> <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/> </resultMap> <select id="getStudentByTeacherId" resultType="Student"> select * from student where tid =#{tid} </select> </mapper>
/** * Teacher(id=1, name=王老师, students=[ * Student(id=1, name=小明, tid=1), * Student(id=2, name=小红, tid=1), * Student(id=3, name=小张, tid=1), * Student(id=4, name=小李, tid=1), * Student(id=5, name=小王, tid=1)] * ) * */
-
注:复杂的属性,需要单独处理 对象使用:association 集合:collection 。javaType:表字段类型定义为Java的复杂类型;javaType:指定属性的类型(eg:Student student)ofType:指定集合中的泛型信息,使用ofType获取
五、动态SQL
1、什么是动态SQL
-
动态SQL就是指根据不同的条件(业务场景)生成不同的SQL语句
-
例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
2、搭建环境
-
sql
CREATE TABLE `blog`( `id` VARCHAR(50) NOT NULL COMMENT '博客id', `title` VARCHAR(100) NOT NULL COMMENT '博客标题', `author` VARCHAR(30) NOT NULL COMMENT '博客作者', `create_time` DATETIME NOT NULL COMMENT '创建时间', `views` INT(30) NOT NULL COMMENT '浏览量' )ENGINE=INNODB DEFAULT CHARSET=utf8
-
基础环境如上所示
-
3、添加ID自动生成的工具类
//抑制警告 @SuppressWarnings("all") public class IDUtils { public static String getId(){ //使用UUID自动创建自增id(若删除其中的id还是连续的) return UUID.randomUUID().toString().replace("-",""); } @Test public void test(){ System.out.println(IDUtils.getId()); System.out.println(IDUtils.getId()); System.out.println(IDUtils.getId()); } }
-
4、Blog实体类(与数据的字段不一致)
@Data public class Blog { private String id; private String title; private String author; //与数据的字段不一致(create_time) private Date createTime; private int views; }
解决:
在配置文件中添加settings设置
<!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。--> <setting name="mapUnderscoreToCamelCase" value="true"/>
3、IF
-
用于动态条件判断不同的条件会查询的结果会有所不同
-
比如:在搜索是可以按照姓名查询又可以按照书名查询
-
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog where 1=1 <if test="title != null"> and title like "%"#{title}"%" </if><if test="author != null"> and author = #{author} </if>
这条语句提供了可选的查找文本功能。;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符)。
- test:判断表达式(OGNL)遇见特殊符号应该去写转义字符:&&、''等字符
- where 1=1:在where条件后面加了一条判断1=1,这样当下面if条件中的任何一个判断失败后,都不会影响整个sql语句。
- 建议方式:
用where和if 进行组合,当条件不成立时,if条件后的内容包括and也不会存在,因此不会对整个sql语句产生影响。注意and关键字要放在每个语句中的库表字段赋值的前面。因为,一旦判断不成功, 会把对应的and关键字去掉(还有or关键字)
-
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。当没有条件设置是查找的是全部的数据
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <if test="title != null"> and title like "%"#{title}"%" </if> <if test="author != null"> and author = #{author} </if> </where> </select>
-
测试类
@Test public void queryBlog(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); map.put("title","Ja"); //map.put("author","lijing"); List<Blog> blogs = mapper.queryBlogIF(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
Blog(id=9e82914025964ba08caa0960ddf5160a, title=Java, author=yyb, createTime=Mon Mar 22 22:43:04 CST 2021, views=1000)
4、choose(when、otherwise)
-
有时候,我们不想使用所有的条件,而只是想从多个条件中只选择一个使用。
-
针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from blog <where> <choose> <when test="title != null">and title like "%"#{title}"%"</when> <when test="author != null"> and author = #{author}</when> <otherwise>and views = #{views} </otherwise> </choose> </where> </select>
-
情况一:当没有传入条件时或传入的条件没有符合choose中的条件他会默认执行
的语句但结果肯定是null -
==> Preparing: select * from blog WHERE views = ?
==> Parameters: null -
情况二:当传入的条件符合其中一个就会执行
-
情况三:当传入的条件多个时他只会默认执行第一个传入的参数的when条件
5、trim(where、set)
- set 元素可以用于动态包含需要更新的列,忽略其它不更新的列
- set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
<!--update更新博客--> <update id="updateBlog" parameterType="map"> update mybatis.blog <set> <if test="title != null">title = #{title},</if> <if test="author != null">author = #{author},</if> <if test="views != null"> views = #{views},</if> create_time = now() </set> where id =#{id} </update>
-
通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
-
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
-
set 元素等价的自定义 trim 元素吧:
<trim prefix="SET" suffixOverrides=","> ... </trim>
所谓的动态SQL,本质就是SQL语句,只是我们可以在SQL层面里,去执行一个逻辑代码
6、SQL片段
- 将一些公共(相同)的sql语句抽取出来实现代码的复用
1、使用sql标签抽取公共的部分
<!--使用sql片段将公共的sql提取出来在需要使用的地方引用即可--> <sql id="queryBlog"> <if test="title != null"> and title like "%"#{title}"%" </if> <if test="author != null"> and author = #{author} </if> </sql>
2、在需要使用的地方使用include标签引用即可
<select id="queryBlogIF" parameterType="map" resultType="blog"> select * from blog <where> <include refid="queryBlog"/> </where> </select>
注意点:
-
最好基于单表来定义SQL片段!
SQL片段中不要存在where标签!
7、foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候
<!--只查找博客的前三条记录--> <!--select * from `blog` where 1=1 and (id=1 or id =2 or id=3);--> <select id="queryBlogForeach" resultType="blog" parameterType="map"> select * from blog <where> <foreach collection="ids" item="id" open="and ("open="and ("separator="or"> id = #{id} </foreach> </where> </select>
@Test public void queryBlogForeach(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); HashMap map = new HashMap(); List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); map.put("ids",list); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
-
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(collection="ids")list属性和list中的每个元素(item="id")。它也允许你指定开头open="and ("与结尾的字符串open="and ("以及集合项迭代之间的分隔符separator="or"。这个元素也不会错误地添加多余的分隔符,看它多智能!
-
可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
8、小结:
动态SQL就是在拼接SQL语句,我们只要保证SQL的准确性,按照SQL的格式,去排列组合就可以了
建议:
- 先在Mysql中写出完整的SQL语句测试是否成功,在再xml中写