欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java学习笔记-Day75 MyBatis 框架(二)

程序员文章站 2024-03-24 11:24:34
...



一、Mybatis的日志


Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:SLF4J、Apache Commons Logging、Log4j 2、Log4j、JDK logging。MyBatis 内置日志工厂会基于运行时检测信息选择日志委托实现。它会(按上面罗列的顺序)使用第一个查找到的实现。当没有找到这些实现时,将会禁用日志功能。

(1)添加log4j.jar到项目的构建路径。

Java学习笔记-Day75 MyBatis 框架(二)
(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。

Java学习笔记-Day75 MyBatis 框架(二)

(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的文件夹。

Java学习笔记-Day75 MyBatis 框架(二)

(4)打开DOS命令窗口,进入 generator-cmd 文件夹中,运行如下命令就会生成文件。

java -jar mybatis-generator-core-1.3.5.jar -configfile generator.xml -overwrite
相关标签: 笔记 java