1. 简介 什么是 MyBatis? MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
2. 基本使用 最惯常的使用步骤:
2.1. 在数据库中准备好相应的数据库、数据表等(以 book 表为例) 1 2 3 4 5 6 7 8 9 10 11 12 # 创建表 CREATE TABLE book( id INT , bookName VARCHAR (50 ), price DOUBLE ); # 稍微添加一些数据 INSERT INTO book VALUES (1 , "C语言程序设计", 10 ), (2 , "Python程序设计", 20 ), (3 , "Java程序设计", 30 );
2.2. 新建一个 maven 项目,修改 pom.xml 文件
加入依赖 mybatis、mysql 驱动、junit 测试单元
在 <build> 中加入资源插件(会省去很多麻烦)
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 31 32 33 34 35 36 <properties > <maven.compiler.source > 17</maven.compiler.source > <maven.compiler.target > 17</maven.compiler.target > </properties > <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.9</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.25</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.properties</include > <include > **/*.xml</include > </includes > <filtering > false</filtering > </resource > </resources > </build >
2.3. 在 java 程序中创建实体类 book,定义属性,属性名与数据表列名保持一致 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 31 32 33 34 35 36 37 38 public class Book { private Integer id; private String bookName; private Double price; public int getId () { return id; } public void setId (int id) { this .id = id; } public String getBookName () { return bookName; } public void setBookName (String bookName) { this .bookName = bookName; } public double getPrice () { return price; } public void setPrice (double price) { this .price = price; } @Override public String toString () { return "book实体信息{" + "id=" + id + ", bookName='" + bookName + '\'' + ", price=" + price + '}' ; } }
2.4. 创建 Dao 接口,定义操作数据库的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public interface BookDao { Book selectBookById (Integer id) ; List<Book> selectAllBooks () ; int insertOneBook (Book book) ; }
2.5 创建 mapper 文件(xml 文件),写 sql 语句
mybatis 框架推荐把 sql 语句和 java 代码分开
mapper 文件一般和 Dao 接口文件在同一目录,一般情况下一个表对应一个 mapper 文件
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <?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.pushihao.example.Dao.BookDao" > <select id ="selectBookById" resultType ="com.pushihao.example.domain.Book" > select id, bookName, price from book where id= #{BookId} </select > <select id ="selectAllBooks" resultType ="com.pushihao.example.domain.Book" > select id, bookName, price from book </select > <insert id ="insertOneBook" > insert into book(id, bookName, price) values(#{id}, #{bookName}, #{price}) </insert > </mapper >
2.6 创建 mybatis 的主配置文件(xml 文件)
定义创建连接实例的数据源(DateSource)对象
指定其他 mapper 文件的位置
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 <?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 > <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> </settings > <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://localhost:3306/book" /> <property name ="username" value ="book" /> <property name ="password" value ="book" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="com/pushihao/example/Dao/BookDao.xml" /> </mappers > </configuration >
2.7 创建测试内容 测试的两种方式:
使用 main 方法,测试 mybatis 访问数据库
使用 junit 测试单元访问数据库
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class exampleTest { @Test public void testSelectBookById () throws Exception { String config = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(config); SqlSessionFactory factory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession session = factory.openSession(); String sqlId = "com.pushihao.example.Dao.BookDao.selectBookById" ; Book book = session.selectOne(sqlId, 4 ); System.out.println("使用mybatis查询一本书:" ); System.out.println(book); session.close(); } @Test public void testInsertOneBook () throws Exception { String config = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(config); SqlSessionFactory factory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession session = factory.openSession(); String sqlId = "com.pushihao.example.Dao.BookDao.insertOneBook" ; Book book = new Book (); book.setId(4 ); book.setBookName("概率论与数理统计" ); book.setPrice(20d ); int rows = session.insert(sqlId, book); session.commit(); System.out.println("使用mybatis添加一本书,rows:" + rows); session.close(); } }
3. 简单优化 3.1 创建工具类
可以把创建 SqlSession 的过程封装为一个静态方法封装在工具类中,大大减少不必要的代码量
工具类一般放在 utils 包下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class CreatSqlSession { private static SqlSessionFactory factory = null ; private static final String config = "mybatis-config.xml" ; static { try { InputStream inputStream = Resources.getResourceAsStream(config); factory = new SqlSessionFactoryBuilder ().build(inputStream); } catch (Exception e) { e.printStackTrace(); } } public static SqlSession getSession () { SqlSession session = null ; if (factory != null ) { session = factory.openSession(); } return session; } }
当使用 CreatSqlSession.getSession() 方法时,可以直接得到一个独立的 SqlSession 对象
3.2 实现 BookDao 接口 完成一个 BookDao 接口的实现类,需要使用时可以直接调用其中的方法
创建 BookDao 接口实现类:
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 public class BookDaoImpl implements BookDao { @Override public Book selectBookById (Integer id) { SqlSession session = CreatSqlSession.getSession(); Book book = null ; if (session != null ) { String sqlId = "com.pushihao.example.Dao.BookDao.selectBookById" ; book = session.selectOne(sqlId, id); } return book; } @Override public List<Book> selectAllBooks () { SqlSession session = CreatSqlSession.getSession(); List<Book> books = null ; if (session != null ) { String sqlId = "com.pushihao.example.Dao.BookDao.selectAllBooks" ; books = session.selectList(sqlId); } return books; } @Override public int insertOneBook (Book book) { return 0 ; } }
使用:
1 2 3 4 5 6 @Test public void testBookDaoImpl () { BookDao dao = new BookDaoImpl (); List<Book> books = dao.selectAllBooks(); books.forEach(System.out::println); }
4. 使用 Dao 代理
所谓 Dao 代理就是指 mybatis 创建一个对象用于代替我们自己创建的 Dao 接口的实现类,完成 sql 语句的执行
使用代理后,就不需要自己写实现类了,只需要给定接口和 mapper 文件就可以直接使用
使用 mybatis 代理的要求:
mapper 文件中的 namespace 一定要为 dao 接口的全限定名称
mapper 文件中的标签的 id 是 dao 接口的方法(函数)名称
实现方式:
使用 SqlSession 对象的 getMapper 方法,参数为 Dao 接口的 class 对象
1 2 3 4 5 6 7 8 9 @Test public void testProxy () { SqlSession session = CreatSqlSession.getSession(); if (session != null ) { BookDao dao = session.getMapper(BookDao.class); Book book = dao.selectBookById(1 ); System.out.println(book); } }
5. mybatis 传递参数
参数一般指占位符 #{} 里面的内容,由于内容是可变的,所以叫参数
说明:parameterType 参数类型
在 select 等标签属性可以给定 parameterType 参数类型
此属性不是必须的,即使不写 mybatis 也能猜出来
指可以为 java 的全限定名称或者为 mybatis 给出的别名
5.1 参数为一个简单类型 当对 sql 语句传递的参数为一个简单类型时,参数名称可以随意命名,不过尽量起的有意义些
1 2 3 4 public interface BookDao { Book selectBookById (Integer id) ; }
1 2 3 4 <select id ="selectBookById" resultType ="com.pushihao.domain.Book" > select * from book where id=#{id} </select >
1 2 3 4 5 6 7 8 @Test public void testSelectBookById () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); Book book = dao.selectBookById(1 ); System.out.println(book); sqlSession.close(); }
5.2 使用 Param 命名参数 当参数有多个时,可以使用 Param 注解对参数进行命名,在 mapper 文件中需使用命名的值
1 2 3 4 public interface BookDao { List<Book> selectByNameOrPrice (@Param("name") String name, @Param("price") Double price) ; }
1 2 3 4 <select id ="selectByNameOrPrice" resultType ="com.pushihao.domain.Book" > select id,bookName,price from book where bookName=#{name} or price=#{price} </select >
1 2 3 4 5 6 7 8 9 10 @Test public void testSelectByNameOrPrice () { SqlSession sqlSession = CreatSqlSession.getSession(); if (sqlSession != null ) { BookDao dao = sqlSession.getMapper(BookDao.class); List<Book> books = dao.selectByNameOrPrice("C语言程序设计" , 20d ); books.forEach(System.out::println); sqlSession.close(); } }
5.3 参数为一个 java 对象 1 2 3 4 public interface BookDao { Book isBookExist (Book book) ; }
1 2 3 <select id ="isBookExist" resultType ="com.pushihao.domain.Book" > select * from book where id=#{id} and bookName=#{bookName} and price=#{price} </select >
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void testIsBookExist () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); Book book = new Book (); book.setBookName("C语言程序设计" ); book.setId(1 ); book.setPrice(10.0d ); Book book1 = dao.isBookExist(book); System.out.println(book1); sqlSession.close(); }
使用此方法时占位符中的参数即为 java 对象的属性值,其实是调用了 java 对象的 get 方法获取了属性的值。所以此对象一定要有相应的 getter 和 setter 方法
参数的完整写法为:#{property, javaType=java中的数据类型名, jdbcType=jdbc数据类型名}
javaType、jdbcType 的类型可以由 mybatis 检测出来,一般不需要设置。只需要写上属性名即可
5.4 按位置传递参数 参数位置从 0 开始,引用参数语法 #{arg位置},如:第一个参数是 #{arg0},第二个是 #{arg1}
注意:mybatis-3.3 版本和之前的版本使用 #{0}, #{1} 方式,从 mybatis-3.4 开始使用 #{arg0} 方式
此方法可读性较差,一般很少使用
1 2 3 4 public interface BookDao { List<Book> selectByIdAndName (Integer id, String bookName) ; }
1 2 3 4 <select id ="selectByIdAndName" resultType ="com.pushihao.domain.Book" > select * from book where id=#{arg0} and bookName=#{arg1} </select >
1 2 3 4 5 6 7 8 @Test public void testSelectByIdAndName () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); List<Book> books = dao.selectByIdAndName(1 , "C语言程序设计" ); sqlSession.close(); books.forEach(System.out::println); }
5.5 使用 Map 类型传递参数 Map 集合可以存储多个值,使用 Map 集合可以向 mapper 文件一次传入多个参数。
Map 集合的 key 要为 String 类型,value 可以为 Object 类型
mapper 文件使用 #{ key } 来调用参数值
1 2 3 4 public interface BookDao { Book selectBookByNameAndPrice (Map<String, Object> map) ; }
1 2 3 4 <select id ="selectBookByNameAndPrice" resultType ="com.pushihao.domain.Book" > select * from book where bookName=#{name} and price=#{price} </select >
1 2 3 4 5 6 7 8 9 10 11 @Test public void testSelectBookByNameAndPrice () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); Map<String, Object> map = new HashMap <>(); map.put("name" , "C语言程序设计" ); map.put("price" , 10d ); Book book = dao.selectBookByNameAndPrice(map); sqlSession.close(); System.out.println(book); }
6. 封装 mybatis 输出结果 封装输出结果:mybatis 执行 sql 语句,得到相应的结果 ResultSet,并将结果转换为 java 对象
封装结果可以使用 resultType,也可以使用 resultMap
6.1 resultType
在执行 select 时使用,作为 <select> 标签的属性出现
表示执行 sql 语句后,得到的 java 对象的类型,它有两种取值:
java 类型全限定名称(可以是内置类型,也可以是自定义类型)
使用别名
自定义别名:mybatis 提供的使我们可以对 java 类型进行自定义简短好记的名称
自定义别名的步骤:
声明:在 mybatis 主配置文件中,使用 typeAliases 标签进行声明别名
使用:在 mapper 文件中,可以直接使用 resultType=”别名”
1 2 3 4 5 6 7 8 9 10 <typeAliases > <typeAlias type ="com.pushihao.pojo.book" alias ="book" /> <package name ="com.pushihao.pojo" /> </typeAliases >
一般情况下使用类的全限定名称就好了,使用自定义别名会使可读性降低(不推荐)
resultType 的值也可以有多种情况:
前两种比较相似(直接用即可)
6.1.1 自定义 java 类型 6.1.2 简单类型 6.1.3 输出结果为 Map 类型 1 Map<Object, Object> selectByBookId (@Param("id") Integer id) ;
1 2 3 4 <select id ="selectByBookId" resultType ="map" > select * from book where id=#{id} </select >
1 2 3 4 5 6 7 8 @Test public void testSelectByBookId () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); Map<Object, Object> map = dao.selectByBookId(1 ); sqlSession.close(); System.out.println(map); }
sql 语句执行得到的结果是:列名作为 map 的 key,列值作为 map 的 value
只能得到一行记录,当有多行记录时,此方法会报错
6.2 resultMap(比较常用) resultMap:结果映射。自定义列名和 java 对象属性的对应关系。常用于列名和属性名不同的情况
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <resultMap id ="customMap" type ="com.pushihao.pojo.book" > <id column ="id" property ="cid" /> <result column ="name" property ="cname" /> </resultMap > <select id ="selectById" resultMap ="customMap" > select id, name, email, age from student where id = #{studentId} </select >
同一个 resultMap 标签可以进行多次使用
6.3 列名和 java 对象属性名称不一致的解决方案
使用列别名解决此问题(resultType 的)
1 2 3 <select id ="selectById" resultType ="com.pushihao.pojo.book" > select id as cid, name as cname, email, age from student where id = #{studentId} </select >
使用 resultMap 做映射(上面已经提到)
7. 占位符
占位符主要有 #{} 和 ${} 两种,语法非常相似,但是原理和使用场景有些不同
7.1 # 占位符 语法:#{ 字符 }
mybatis 处理 #{} 使用的 jdbc 对象是 PrepareStatment 对象
特点:
使用的是 PrepareStatment 对象来执行 sql 语句,效率更高
能避免 sql 注入的风险,使 sql 语句的执行更加安全
#{} 常常作为列值来使用,位于等号右侧,#{} 位置的值和数据类型是有关的
7.2 $ 占位符 语法:${ 字符 }
特点:
使用 Statment 对象,效率相对较低
${} 占位符执行 sql 语句时,使用的是字符串连接的方式,有 sql 注入的风险,即存在代码安全的问题
${} 中数据是原样使用的,不会区分数据类型(字符串也不会自己加引号,需要手动添加)
${} 常用作表名或者列名,在能保证数据安全的情况下才使用
8. mybatis 使用 like 子句
在 MySQL 中,like 子句主要用于模糊查询,% 代表需要模糊的位置
有两种方式可以实现模糊查询
8.1 在 java 程序中,把 like 语句的内容组装好,直接把整个内容传入 xml 中 sql 语句 1 2 List<Book> selectBooksByVagueName (@Param("myName") String name) ;
1 2 3 4 <select id ="selectBooksByVagueName" resultType ="com.pushihao.domain.Book" > select * from book where bookName like #{myName} </select >
1 2 3 4 5 6 7 8 9 @Test public void testSelectBooksByVagueName () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); List<Book> books = dao.selectBooksByVagueName("%程序%" ); sqlSession.close(); books.forEach(System.out::println); }
8.2 在 mapper 文件的 sql 语句中,组装 like 内容 格式:where bookName like “%” #{myName} “%” (中间的空格不能省)
1 2 List<Book> selectBooksBySurname (@Param("surname") String surname) ;
1 2 3 4 <select id ="selectBooksBySurname" resultType ="com.pushihao.domain.Book" > select * from book where bookName like #{surname} "%" </select >
1 2 3 4 5 6 7 8 9 @Test public void testSelectBooksBySurname () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); List<Book> books = dao.selectBooksBySurname("概" ); sqlSession.close(); books.forEach(System.out::println); }
9. 动态 sql
什么是动态 sql:同一个 dao 中的方法,根据不同的条件可以表示不同的 sql 语句。主要是 where 部分有变化
通过使用 mybatis 提供的标签,可以实现动态 sql 的能力,主要有 if,where,foreach,sql 等。
使用动态 sql 时,dao 方法的形参为 java 对象
9.1 if 标签
根据判断条件,判断是否需要执行某段 sql 代码
语法:
1 2 3 4 5 6 <if test ="boolean类型判断结果" > sql 代码 </if > <if test ="boolean类型判断结果" > sql 代码 </if >
当 test 中的 boolean 值为 true 时,其中的 sql 代码会被**直接 **拼接到主 sql 语句上
在 test 属性中可以直接使用传入 java 对象的属性,不用加占位符
if 语句可以有多个,不需要使用 else
多个 sql 语句连接时可能会出现语法错误,需要自习考虑
1 Book selectIf (Book book) ;
1 2 3 4 5 6 7 <select id ="selectIf" resultType ="com.pushihao.domain.Book" > select * from book where id=-1 <if test ="bookName != null and bookName != ''" > or bookName=#{bookName} </if > </select >
1 2 3 4 5 6 7 8 9 10 11 @Test public void testSelectIf () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); Book book = new Book (); book.setBookName("" ); Book result = dao.selectIf(book); sqlSession.close(); System.out.println(result); }
注意:在 sql 中直接使用大于号(>)和小于号(<)会报错,因为它与标签的起止标记重复了。为了解决这个问题,需要使用实体符号
<
<=
>
>=
&
‘
“
小于号
小于等于
大于号
大于等于
& 符号
单引号
双引号
<
<=
>
>=
&
'
"
9.2 where 标签
为了解决 if 标签导致的语法问题,引入了 where 标签
语法:
1 2 3 4 <where > <if test ="条件1" > sql语句1</if > <if test ="条件2" > sql语句2</if > </where >
where 标签里面是一个或多个 if 标签,当至少有一个 if 标签的判断条件为 true 时,where 标签会自动在主 sql 语句后添加 WHERE 关键字,如果没有一个条件为 true,则忽略此标签
同时,where 标签还会自动删除紧跟的第一条语句的 and 或 or 语句,避免引起语法错误
1 Book selectWhere (Book book) ;
1 2 3 4 5 6 7 8 9 10 11 <select id ="selectWhere" resultType ="com.pushihao.domain.Book" > select * from book <where > <if test ="bookName == null or bookName == ''" > or id=-1 </if > <if test ="bookName != null and bookName != ''" > or bookName=#{bookName} </if > </where > </select >
1 2 3 4 5 6 7 8 9 10 11 @Test public void testSelectWhere () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); Book book = new Book (); book.setBookName("C语言程序设计" ); Book result = dao.selectWhere(book); sqlSession.close(); System.out.println(result); }
9.3 foreach 标签
foreach 标签可以更加方便地遍历一个数组或者一个 List 集合
为了更清楚地解释其中的参数,先进行一个手工实现的 foreach 循环做个对比
9.3.1 手工实现 foreach 循环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Test public void testHandmadeForeach () { List<Integer> idList = new ArrayList <>(); idList.add(1 ); idList.add(2 ); idList.add(3 ); StringBuilder sql = new StringBuilder ("select * from book where id in" ); sql.append('(' ); for (int i = 0 ; i < idList.size(); i++) { Integer item = idList.get(i); sql.append(item); sql.append(',' ); } sql.deleteCharAt(sql.length() - 1 ); sql.append(')' ); System.out.println(sql); }
9.3.2 mybatis 实现 foreach 循环
使用 foreach 可以循环遍历数组、List 集合等,一般用在 in 语句中
语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <foreach collection ="集合类型" open ="开始的字符" close ="结束的字符" item ="为集合中的成员命名" separator ="集合成员之间的分隔符" > #{item 的值(用刚刚命的名表示)} </foreach > 标签属性: collection:表示循环对象类型,数组用 collection="array",List 集合用 collection="list" open:开始的字符,相当于 sql.append('('); close:结束的字符,相当于 sql.append(')'); item:集合成员,为自定义的变量,相当于 Integer item = idList.get(i); separator:集合成员之间的分隔符,相当于 sql.append(','); #{item}:获取item中的值,如果为简单类型,直接使用命名的 item,如果为 java 对象类型,使用 命名的 item.属性名 来获取属性值
foreach 简单类型的 List
1 List<Book> selectForeachOne (List<Integer> list) ;
1 2 3 4 5 6 <select id ="selectForeachOne" resultType ="com.pushihao.domain.Book" > select * from book where id in <foreach collection ="list" open ="(" close =")" item ="singleId" separator ="," > #{singleId} </foreach > </select >
1 2 3 4 5 6 7 8 9 10 11 @Test public void testSelectForeachOne () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); List<Integer> list = new ArrayList <>(); list.add(1 ); list.add(2 ); list.add(4 ); List<Book> books = dao.selectForeachOne(list); books.forEach(System.out::println); }
foreach 实现对象类型的 List
1 List<Book> selectForeachTwo (List<Book> books) ;
1 2 3 4 5 6 <select id ="selectForeachTwo" resultType ="com.pushihao.domain.Book" > select * from book where id in <foreach collection ="list" open ="(" close =")" item ="book" separator ="," > #{book.id} </foreach > </select >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public void testSelectForeachTwo () { SqlSession sqlSession = CreatSqlSession.getSession(); BookDao dao = sqlSession.getMapper(BookDao.class); List<Book> books = new ArrayList <>(); Book book1 = new Book (); Book book2 = new Book (); Book book3 = new Book (); book1.setId(1 ); book2.setId(4 ); book3.setId(3 ); books.add(book1); books.add(book2); books.add(book3); List<Book> bookList = dao.selectForeachTwo(books); bookList.forEach(System.out::println); }
注意:使用 foreach 遍历的对象 list 为空时,程序会报错,建议在遍历时使用 if 标签套起来
9.4 sql 标签
sql 标签用于定义 sql 代码片段,以便在其他 sql 标签中能够复用此段代码。此 sql 代码片段可以为 sql 语句的任何部分,因此,其他语句也可以在任何地方引用此 sql 代码片段
使用方式:
1 2 3 1.在 mapper 文件中定义 sql 代码片段:<sql id ="唯一标识符" > sql 代码片段</sql > 2.在其他位置使用:<include refid ="要引用的sql语句的id" />
比较简单,如:
1 2 3 4 5 6 7 <sql id ="information" > id, bookName, price </sql > <select id ="selectSql" resultType ="com.pushihao.domain.Book" > select <include refid ="information" /> from book </select >