Java学习笔记-Day75 MyBatis 框架(二)
Java学习笔记-Day75 MyBatis 框架(二)
一、Mybatis的日志
Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:SLF4J、Apache Commons Logging、Log4j 2、Log4j、JDK logging。MyBatis 内置日志工厂会基于运行时检测信息选择日志委托实现。它会(按上面罗列的顺序)使用第一个查找到的实现。当没有找到这些实现时,将会禁用日志功能。
(1)添加log4j.jar到项目的构建路径。
(2)添加log4j.properties配置文件到src目录下。
- log4j.properties
# 全局日志配置
log4j.rootLogger=ERROR, stdout
# MyBatis 日志配置
log4j.logger.com.etc.mybatis.dao=TRACE
log4j.logger.com.etc.mybatis.test=DEBUG
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
(3)通过Logger(org.apache.log4j.Logger)类来输出数据。
public class TestLogger {
public static void main(String[] args) throws IOException {
Logger logger = Logger.getLogger(TestLogger .class);
logger.debug("debug"); // debug、info、warn、error
logger.info("info");
logger.warn("warn");
logger.error("error");
}
}
二、动态SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
- if
- choose、when、otherwise
- trim、where、set
- foreach
1、if
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。
<select id="selectBlog" resultType="com.etc.mybatis.entity.Blog">
SELECT * FROM blog
WHERE state = 1
<if test="title != null">
AND title like #{title}
</if>
<if test="content != null">
AND content like #{content}
</if>
</select>
2、choose 、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。如果传入了 title 就按 title 查找,传入了 content 就按 content 查找,若两者都没有传入,就返回 featured 为 1 的 blog。
<select id="selectBlog" resultType="Blog">
SELECT * FROM blog WHERE status = 1
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="content != null">
AND content like #{content}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
3、trim 、where、 set
(1)where 元素只会在子元素返回任何内容的情况下才插入 WHERE 子句。若子句的开头为 AND 或 OR,where 元素也会将它们去除。
<select id="selectBlogByLike" resultType="com.etc.mybatis.entity.Blog">
SELECT * FROM blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="content != null">
AND content like #{content}
</if>
</where>
</select>
如果 where 元素与你期望的不太一样,也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
(2)set元素用于动态更新。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
<update id="updateBlog">
update blog
<set>
<if test="title != null">blogtitle=#{blogtitle},</if>
<if test="content != null">content=#{content}</if>
</set>
where blogid=#{id}
</update>
与 set 元素等价的自定义 trim 元素:
<trim prefix="SET" suffixOverrides=",">
...
</trim>
该trim元素覆盖了后缀值设置,并且自定义了前缀值。
4、foreach
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
foreach元素的常见使用场景:(1)查询数据 (2)批量删除数据
4.1、查询数据
- BlogMapper.xml
<select id="selectBlogs" resultMap="blogResultMap">
SELECT * FROM blog WHERE blogid in
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<resultMap id="blogResultMap" type="com.etc.mybatis.entity.Blog" >
<id property="id" column="blogid"/>
<result property="title" column="blogtitle"/>
<result property="content" column="blogcontent"/>
</resultMap>
- BlogMapper.java
public interface BlogMapper {
public boolean selectBlogs(List<Integer> ids);
}
- TestBlogSelect.java
public class TestBlogDelete {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
List<Blog> bloglist = mapper.selectBlogs(list);
System.out.println(bloglist);
session.close();
inputStream.close();
}
}
4.2、批量删除数据
- BlogMapper.xml
<delete id="deleteBlogs">
delete from blog
WHERE blogid in
<foreach item="item" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</delete>
- BlogMapper.java
public interface BlogMapper {
public boolean deleteBlogs(List<Integer> ids);
}
- TestBlogDelete.java
public class TestBlogDelete {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
boolean flag = mapper.deleteBlogs(list);
// 手动提交事务
session.commit();
session.close();
inputStream.close();
System.out.println("flag="+flag);
}
}
5、注解形式的动态SQL
public interface BlogMapper {
@Select(value = "select * from blog where blogid = #{id}")
@Results(id = "blogResultMap", value = { @Result(property = "id", column = "blogid", id = true),@Result(property = "title", column = "blogtitle"), @Result(property = "content", column = "blogcontent") })
public Blog selectBlog(int id);
@SelectProvider(type = BlogSqlBuilder.class, method = "buildGetBlogsByLike")
@ResultMap(value="blogResultMap")
public List<Blog> selectBlogByLike(@Param("title") String title, @Param("content") String content);
public class BlogSqlBuilder {
public static String buildGetBlogsByLike(@Param("title") final String title, @Param("content") final String content) {
return new SQL() {
{
SELECT("*");
FROM("blog");
if(title != null) {
WHERE("blogtitle like #{title}");
}
if(content != null) {
OR();
WHERE("blogcontent like #{content}");
}
}
}.toString();
}
}
}
三、关联映射
(1)关联单个对象,使用 resultMap 中的 association(一个复杂的类型关联,许多结果将包成这种类型)。
- Blog.java
package com.etc.mybatis.entity;
public class Blog {
private int id;
private String title;
private String content;
// 关联一个对象(association)
private Author author;
public Blog(int id, String title, String content) {
super();
this.id = id;
this.title = title;
this.content = content;
}
public Blog() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Author getAuthor() {
return author;
}
public void setAuthor(Author author) {
this.author = author;
}
@Override
public String toString() {
return "Blog [id=" + id + ", title=" + title + ", content=" + content + ", author=" + author + "]";
}
}
- BlogMapper.java
package com.etc.mybatis.dao;
import java.util.List;
import com.etc.mybatis.entity.Blog;
public interface BlogMapper {
public List<Blog> selectBlog(int blogid);
}
- BlogMapper.xml
<?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.etc.mybatis.dao.BlogMapper">
<select id="selectBlog" resultMap="blogResultMap">
select blog.blogid,blog.blogtitle,blog.blogcontent,author.authorid,author.authorname,author.authorage
from blog inner join author on blog.authorid=author.authorid where blog.blogid=#{id}
</select>
<resultMap id="blogResultMap" type="com.etc.mybatis.entity.Blog" >
<id property="id" column="blogid"/>
<result property="title" column="blogtitle"/>
<result property="content" column="blogcontent"/>
<!-- 关联一个Author对象 -->
<association property="author" column="authorid" javaType="com.etc.mybatis.entity.Author">
<id property="id" column="authorid"/>
<result property="name" column="authorname"/>
<result property="age" column="authorage"/>
</association>
</resultMap>
</mapper>
- TestBlogSelect.java
package com.etc.mybatis.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.etc.mybatis.dao.BlogMapper;
import com.etc.mybatis.entity.Blog;
public class TestBlogSelect {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
List<Blog> list = mapper.selectBlog(1);
System.out.println(list);
}
}
(2)关联多个对象,使用 resultMap中的 collection(复杂类型的集)。
- Author.java
package com.etc.mybatis.entity;
import java.util.List;
public class Author {
private int id;
private String name;
private int age;
// 关联多个Blog对象(collection)
private List<Blog> blogs;
public Author(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public Author() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Blog> getBlogs() {
return blogs;
}
public void setBlogs(List<Blog> blogs) {
this.blogs = blogs;
}
@Override
public String toString() {
return "Author [id=" + id + ", name=" + name + ", age=" + age + ", blogs=" + blogs + "]";
}
}
- AuthorMapper.java
package com.etc.mybatis.dao;
import org.apache.ibatis.annotations.Param;
import com.etc.mybatis.entity.Author;
public interface AuthorMapper {
public Author selectAuthor(int id);
}
- AuthorMapper.xml
<?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.etc.mybatis.dao.AuthorMapper">
<select id="selectAuthor" resultMap="authorResultMap">
select blog.blogid,blog.blogtitle,blog.blogcontent,author.authorid,author.authorname,author.authorage from blog inner join author on blog.authorid=author.authorid where author.authorid=#{id}
</select>
<resultMap id="authorResultMap" type="com.etc.mybatis.entity.Author" >
<id property="id" column="authorid"/>
<result property="name" column="authorname"/>
<result property="age" column="authorage"/>
<!-- 关联多个Blog对象 -->
<collection property="blogs" ofType="com.etc.mybatis.entity.Blog">
<id property="id" column="blogid"/>
<result property="title" column="blogtitle"/>
<result property="content" column="blogcontent"/>
</collection>
</resultMap>
</mapper>
- TestAuthorSelect.java
package com.etc.mybatis.test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.etc.mybatis.dao.AuthorMapper;
import com.etc.mybatis.entity.Author;
public class TestAuthorSelect {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
AuthorMapper mapper = session.getMapper(AuthorMapper.class);
Author author = mapper.selectAuthor(1);
System.out.println(author);
}
}
四、MyBatis-Generator的使用
使用MyBatis的Generator插件,可以快速的生成数据库表对应的实体类、Dao层接口以及其sql映射接口文件。
(1)generator-cmd文件夹中应包含 mybatis-generator-core-1.3.5.jar、mysql-connector-java-5.1.6.jar 和 generator.xml。
(2)修改generator.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动包位置 -->
<classPathEntry location="mysql-connector-java-5.1.6.jar" />
<context id="DB2Tables" targetRuntime="MyBatis3">
<!-- 为了防止生成的代码中有很多注释,比较难看,加入下面的配置控制 -->
<commentGenerator>
<property name="suppressAllComments" value="true" />
<property name="suppressDate" value="true" />
</commentGenerator>
<!-- 注释控制完毕 -->
<!-- 数据库链接URL、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybaisdb?useUnicode=true&bmp;characterEncoding=UTF-8&bmp;serverTimezone=Asia/Shanghai" userId="root"
password="root">
<!--
oracle 数据库连接的信息 <jdbcConnection
driverClass="oracle.jdbc.driver.OracleDriver"
connectionURL="jdbc:oracle:thin:@localhost:1521:orcl" userId="scott"
password="tiger">
-->
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 生成实体类的包名和位置,这里配置将生成的实体类放在com.etc.entity这个包下 -->
<javaModelGenerator targetPackage="com.etc.entity"
targetProject="src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- 生成的SQL映射文件包名和位置,这里配置将生成的SQL映射文件放在com.etc.mapping这个包下 -->
<sqlMapGenerator targetPackage="com.etc.mapping"
targetProject="src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- 生成DAO的包名和位置,这里配置将生成的dao类放在com.etc.dao这个包下 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.etc.dao" targetProject="src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 要生成那些表(更改tableName和domainObjectName就可以) -->
<table tableName="blog" domainObjectName="Blog"
enableCountByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableSelectByExample="false"
selectByExampleQueryId="false" />
</context>
</generatorConfiguration>
(3)在 generator-cmd 文件夹中创建一个名为src的文件夹。
(4)打开DOS命令窗口,进入 generator-cmd 文件夹中,运行如下命令就会生成文件。
java -jar mybatis-generator-core-1.3.5.jar -configfile generator.xml -overwrite