Mybatis入门教程

目录

1. 配置环境

1.1 导入jar

1.2 配置连接

2. mybatis的简单创建

3. mybatis的执行流程

4. 更多操作用例

5. 动态sql

5.1 利用if语句查询

5.2 利用choose语句查询

5.3 "trim"标签的使用

5.4 更新

5.5 批量删除

6. 逆向工程

6.1 generator.xml配置

6.2 实现类

7. 逆向工程的使用与扩展

8. 嵌套查询

8.1 一对一查询

8.2 多对一查询

8.3 嵌套结果查询

9. 缓存

9.1 一级缓存

9.2 二级缓存

10. 鉴别器

11. 加载类型


1. 配置环境

1.1 导入jar

创建普通java项目

核心jar包

  • log4j-1.2.17.jar
  • mybatis-3.4.6.jar
  • mysql-connector-java-8.0.11.jar

关于延迟加载的jar

  • cglib-3.2.5.jar
  • asm-5.2.jar

1.2 配置连接

将db.properties,log4j.properties,mybatis-config.xml创建到src下

mybatis-config.xml实例如下:

<?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>
        <!--加载db.properties-->
	<properties resource="db.properties"></properties>
	<!-- 定义别名,之后该包的类就不用写完整路径名,可以直接写类名 -->
	<typeAliases>
		<package name="cn.itcast.mybatis.pojo" />
	</typeAliases>
	<!-- 定义数据源 -->
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<!-- 映射(接口)文件 -->
	<mappers>
		<package name="cn.itcast.mybatis.mapper" />
	</mappers>
</configuration>

上面的db.properties实例如下:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
jdbc.username=root
jdbc.password=123

打印信息的log4j.properties实例如下:

### 设置Logger输出级别和输出目的地 ###

log4j.rootLogger=debug,stdout,logfile

### 把日志信息输出到控制台 ###

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout


### 把日志信息输出到文件:jbit.log ###
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=jbit.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %F %p %m%n


###显示SQL语句部分
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

 mybatis-config.xml需要加载,所以创建包cn.itcast.mybatis.util下创建MyBatisUtil.java实例:

public class MyBatisUtil {
	private static SqlSessionFactory sqlSessionFactory = null;
	/**
	 * 获取SqlSessionFactory
	 * 用静态代码块进行创建SqlSessionFactory,只在类加载时创建一次,保证了整个程序运行时只有一个工厂实例。
	 */
	static {
		InputStream in;
		try {
			in = Resources.getResourceAsStream("mybatis-config.xml");
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private MyBatisUtil() {
	};

	/**
	 * 获取SqlSession
	 * @return SqlSession
	 */
	public static SqlSession getSqlSession() {
		return sqlSessionFactory.openSession();
	}
}

至此环境配置完成!

2. mybatis的简单创建

创建项目一

数据库实例:

/*
SQLyog Ultimate v12.09 (64 bit)
MySQL - 8.0.11 : Database - mybatis
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`mybatis` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;

USE `mybatis`;

/*Table structure for table `blog` */

DROP TABLE IF EXISTS `blog`;

CREATE TABLE `blog` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `title` varchar(150) COLLATE utf8_bin DEFAULT NULL,
  `authorId` int(10) DEFAULT NULL,
  `state` varchar(300) COLLATE utf8_bin DEFAULT NULL,
  `featured` tinyint(1) DEFAULT NULL,
  `style` varchar(150) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

/*Data for the table `blog` */

insert  into `blog`(`id`,`title`,`authorId`,`state`,`featured`,`style`) values (1,'武器Trim',1,'ACTIVE',1,'red'),(2,'sd',2,'ACTIVE',1,'red'),(4,'qweqew',3,'NO ACTIVE',1,'red'),(5,'hhh',1,'NO ACTIVE',0,'black'),(6,'HEwk',1,'ACTIVE',1,'black'),(7,'hEwk',4,'ACTIVE',1,'black'),(28,'行政28',2,'ACTIVE',0,'pink');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

根据上面的mybatis-config.xml别名映射

创建包cn.itcast.mybatis.pojo,创建Blog类实例:

package cn.itcast.mybatis.pojo;

import java.io.Serializable;

public class Blog {
	private Integer id;
	private String title;
	private Integer authorId;
	private String state;
	private Boolean featured;
	private String style;
	
	public Blog() {
		super();
//              插入时用
//		this.title="插入";
//		this.authorId=2;
//		this.state="ACTIVE";
//		this.featured=true;
//		this.style="pink";			
	}
        //后面自行填充
}

根据最后的映射文件所以创建包cn.itcast.mybatis.mapper

创建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">
<!-- 绑定Dao接口,之后,你可以不用写接口实现类,
mybatis会通过与id同名的接口自动帮你找到对应要执行的SQL语句 -->
<mapper namespace="cn.itcast.mybatis.mapper.BlogMapper">

	<!-- 实现类名,返回值别名,传入参数类型为Integer -->
        <!-- statement -->
	<select id="selectBlog" resultType="Blog" parameterType="int">
		select *
		from blog where id = #{id}
	</select>
</mapper>

创建对应接口BlogMapper.java:

public interface BlogMapper {
	Blog selectBlog(Integer id);
}

配置完成,接下来创建测试类,在根目录下创建test文件夹,创建cn.itcast.mybatis.mapper以及测试类BlogMapperTest.java实例如下:

public class BlogMapperTest {
	// 根据id查询1条记录
	@Test
	public void testSelectBlog() {
                //获取SqlSession
		SqlSession session = MyBatisUtil.getSqlSession();
                //解析class文件获取接口方法
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Blog blog = blogMapper.selectBlog(1);	
		System.out.println(blog);
		session.close();
	}

检查一下目录结构:

 

Mybatis中javaType和jdbcType对应关系

 JDBCType            JavaType
    CHAR                String
    VARCHAR             String
    LONGVARCHAR         String
    NUMERIC             java.math.BigDecimal
    DECIMAL             java.math.BigDecimal
    BIT                 boolean
    BOOLEAN             boolean
    TINYINT             byte
    SMALLINT            short
    INTEGER             int
    BIGINT              long
    REAL                float
    FLOAT               double
    DOUBLE              double
    BINARY              byte[]
    VARBINARY           byte[]
    LONGVARBINARY               byte[]
    DATE                java.sql.Date
    TIME                java.sql.Time
    TIMESTAMP           java.sql.Timestamp
    CLOB                Clob
    BLOB                Blob
    ARRAY               Array
    DISTINCT            mapping of underlying type
    STRUCT              Struct
    REF                 Ref
    DATALINK            java.net.URL[color=red][/color]

3. mybatis的执行流程

从上方的测试用例逐句分析

SqlSession session = MyBatisUtil.getSqlSession();

1. 实例化静态代码块的sqlSessionFactory并加载mybatis-config.xml实现数据库连接并映射接口

2. mybatis-config.xml的<mappers>节点会映射cn.itcast.mybatis.mapper包下文件

3. 通过sqlSessionFactory.openSession()获取SqlSession对象

BlogMapper blogMapper = session.getMapper(BlogMapper.class);

4. 这里通过SqlSession.getMapper(BlogMapper.class) 方法,MyBatis 会根据相应的接口声明的方法信息,通过动态代理机制生成一个BlogMapper 实例blogMapper

Blog blog = blogMapper.selectBlog(1);    

5. 使用BlogMapper 接口的方法时,MyBatis 会自动确定BlogMapper.xml 的statement Id执行sql语句

6. statement中的结果映射对执行结果进行转换处理,并得到最终的处理结果给blog

System.out.println(blog);
session.close();

7. 打印结果并关闭连接

4. 更多操作用例

更多操作的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">
<!-- 绑定Dao接口,之后,你可以不用写接口实现类,
mybatis会通过与id同名的接口自动帮你找到对应要执行的SQL语句 -->
<mapper namespace="cn.itcast.mybatis.mapper.BlogMapper">
	<!-- 定义sql片段 -->
	<sql id="columnBase">
		`title`,
		`authorId`,
		`state`,
		`featured`,
		`style`
	</sql>

	<!-- **************** CRUD *************** -->
	<!-- 实现类名,返回值别名,传入参数类型为Integer -->
	<!-- statement -->
	<select id="selectBlog" resultType="Blog" parameterType="int">
		select *
		from blog where id = #{id}
	</select>
	<!-- #号模糊查询 -->
	<select id="selectBlogByTitle" resultType="Blog"
		parameterType="string">
		select * from blog where title like #{title}
	</select>
	<!-- $字符要加引号,这里将查到的值转为小写 -->
	<select id="selectBlogByTitle1" resultType="Blog"
		parameterType="string">
		select * from blog where lower(title) like
		lower('%${value}%')
	</select>
	<!-- 排序 -->
	<select id="selectBlogBySort" resultType="Blog"
		parameterType="string">
		<!-- ASCⅡ排序 -->
		<!-- select * from blog order by ${value} -->
		<!-- 中文(按 字母)排序 -->
		select * from blog order by CONVERT(${value} USING gbk)
	</select>
	</select>
	<!-- 查询多项,Map -->
	<select id="selectBlogByPage2" resultType="Blog">
		select * from blog
		limit #{offset},#{pagesize}
	</select>
	<!-- 插入 -->
	<!-- 设置是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty 设置的领域模型属性中(用来打印自增的id值),可以在全局变量中配置 -->
	<!-- 还有一种方法并且能适用于没有自增的Oracle -->
	<insert id="insertBlog" parameterType="Blog" useGeneratedKeys="true"
		keyProperty="id">
		INSERT INTO
		`mybatis`.`blog` (
			<include refid="columnBase"></include>
		)
		VALUES
		(
		#{title},
		#{authorId},
		#{state},
		#{featured},
		#{style}
		) ;
	</insert>
	<!-- 可以改几项就写几项,但一般为了方便,不改的变量可以后期处理 -->
	<update id="updateBlog" parameterType="Blog">
		UPDATE
		`mybatis`.`blog`
		SET
		`title` = #{title},
		`authorId` = #{authorId},
		`state` = #{state},
		`featured` = #{featured},
		`style` = #{style}
		WHERE `id` = #{id}
	</update>
        <!-- 删除 -->
	<delete id="deleteBlog" parameterType="int">
		delete from blog where
		id=#{id}
	</delete>
</mapper>

对应的接口方法:

public interface BlogMapper {
	Blog selectBlog(Integer id);
	
	List<Blog> selectBlogByTitle(String title);
	
	List<Blog> selectBlogByTitle1(String title);
	
	List<Blog> selectBlogBySort(String column);
	
	List<Blog> selectBlogByPage2(Map<String,Object>map);
	
	int insertBlog(Blog blog);
	
	int updateBlog(Blog blog);

        int updateBlog1(Blog blog);
	
	int deleteBlog(Integer id); 
}

测试用例:

public class BlogMapperTest {
        //查询一条
	@Test
	public void testSelectBlog() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Blog blog = blogMapper.selectBlog(1);	
		System.out.println(blog);
		session.close();
	}

	// 用#查询title
	@Test
	public void testSelectBlogByTitle() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		List<Blog> blogList = blogMapper.selectBlogByTitle("%h%");	
		System.out.println(blogList);
		session.close();
	}

	// 用$查询title,可以将占位符写在xml
	@Test
	public void testSelectBlogByTitle1() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		List<Blog> blogList = blogMapper.selectBlogByTitle1("h");	
		System.out.println(blogList);
		session.close();
	}

	// 查询并排序,只能用$实现
	@Test
	public void testSelectBlogBySort() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		List<Blog> blogList = blogMapper.selectBlogBySort("title");		
		System.out.println(blogList);
		session.close();
	}

	// 查询多条,map(推荐使用)
	@Test
	public void testSelectBlogByPage2() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Map<String, Object> map = new HashMap<>();
		map.put("offset", 2);
		map.put("pagesize", 3);
		List<Blog> blogList = blogMapper.selectBlogByPage2(map);
		System.out.println(blogList);
		session.close();
	}

	// 插入
	@Test
	public void testInsertBlog() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Blog blog = new Blog();
		int count = blogMapper.insertBlog(blog);
                //更改原表需要提交
		session.commit();		
		System.out.println(count);
		System.out.println(blog);
		session.close();
	}

	// 更新,必须全部改,否则会用对应类型的默认值填充
	@Test
	public void testUpdateBlog() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Blog blog = new Blog();
		blog.setId(1);
		blog.setTitle("修改");
		blog.setAuthorId(1);
		blog.setFeatured(true);
		blog.setState("ACTIVE");
		blog.setStyle("red");

		int count = blogMapper.updateBlog(blog);
		session.commit();
		session.close();
		System.out.println(blog);
		System.out.println("修改了" + count + "条记录");
	}

	// 只更新单个属性,用先查在改的方式解决问题
	@Test
	public void testUpdateBlog1() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);

		Blog blog = blogMapper.selectBlog(1);

		blog.setId(1);
		blog.setTitle("修改1");
		blog.setAuthorId(33);

		int count = blogMapper.updateBlog(blog);
		session.commit();
		session.close();
		System.out.println(blog);
		System.out.println("修改了" + count + "条记录");
	}

	// 删除
	@Test
	public void testDeleteBlog() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);

		int count = blogMapper.deleteBlog(15);
		session.commit();
		session.close();
		System.out.println("修改了" + count + "条记录");
	}
}

根据刚才的分析可以看出,操作本质大同小异

5. 动态sql

省略接口代码

5.1 利用if语句查询

	<!-- 在state = 'ACTIVE'条件下查询输入的字段匹配的项,没有则显示所有state='ACTIVE'的用户 -->
	<select id="selectActiveBlogByTitle" parameterType="string"
		resultMap="BlogResultMap">
		SELECT * FROM blog WHERE state = 'ACTIVE'
		<if test="value!=null and value!=''">
			AND title LIKE '%${value}%'
		</if>
	</select>

 测试用例:

// 动态sql
	@Test
	public void testSelectActiveBlogByTitle() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);

		// List<Blog> blogList=blogMapper.selectActiveBlogByTitle("h");
		List<Blog> blogList = blogMapper.selectActiveBlogByTitle(null);
		session.close();
		System.out.println(blogList);
	}

5.2 利用choose语句查询

<!-- 在state = 'ACTIVE'条件下查询输入的字段 匹配的项,没有则根据style查询,什么都没输入,显示推荐的博客 -->
	<!-- 传入值是对象,所以写属性而不是value -->
	<select id="selectActiveBlogByTitleOrStyle" parameterType="Blog"
		resultMap="BlogResultMap">
		SELECT * FROM blog WHERE state = 'ACTIVE'
		<choose>
			<when test="title!=null and title!=''">
				and lower(title) like lower(#{title})
			</when>
			<when test="style!=null and style!=''">
				and style=#{style}
			</when>
			<otherwise>
				and featured=true
			</otherwise>
		</choose>
	</select>

测试用例:

// 多条件查询choose
	@Test
	public void testSelectActiveBlogByTitleOrStyle() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);

		Blog blog = new Blog();
		blog.setTitle("%h%");
		blog.setStyle("black");
		List<Blog> blogList = blogMapper.selectActiveBlogByTitleOrStyle(blog);
		// List<Blog> blogList =
		// blogMapper.selectActiveBlogByTitleOrStyle(null);
		session.close();
		System.out.println(blogList);
	}

一般采用choose更好 

5.3 "trim"标签的使用

<!-- trim版按需多条件查询 -->
	<select id="selectBlogByConditionTrim" parameterType="Blog"
		resultMap="BlogResultMap">
		SELECT * FROM blog
		<!-- 忽略多余的and或or -->
		<trim prefix="where" prefixOverrides="and | or">
			<if test="style!=null and style!=''">
				and style = #{style}
			</if>
			<if test="title!=null and title!=''">
				and lower(title) like lower(#{title})
			</if>
			<if test="featured!=null">
				and featured=#{featured}
			</if>
		</trim>
	</select>

测试用例同上

5.4 更新

<!-- trim版按需修改指定的列,未指定则不修改 -->
	<update id="updateBlogByConditionTrim" parameterType="Blog">
		UPDATE
		`blog`
		<!-- 忽略后面的","号 -->
		<trim prefix="set" prefixOverrides=",">
			<if test="title!=null">
				`title` = #{title},
			</if>
			<if test="authorId!=null">
				`authorId` = #{authorId},
			</if>
			<if test="state!=null">
				`state` = #{state},
			</if>
			<if test="featured!=null">
				`featured` = #{featured},
			</if>
			<if test="style!=null">
				`style` = #{style}
			</if>
		</trim>
		WHERE `id` = #{id} ;
	</update>

测试用例:

// 更新Trim版
	@Test
	public void testUpdateBlogByConditionTrim() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);

		Blog blog = new Blog();
		blog.setId(1);
		blog.setTitle("武器Trim");
		// blog.setStyle("black");
		int count = blogMapper.updateBlogByCondition(blog);
		session.commit();
		session.close();
		System.out.println(count);
	}

5.5 批量删除

<delete id="deleteBlogList" parameterType="list">
		delete from blog where id in
		<foreach collection="list" item="item" open="(" close=")"
			separator=",">
			#{item}
		</foreach>
	</delete>

测试用例:

// 批量删除id指定范围
	@Test
	public void testDeleteBlogList() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		List<Integer> ids = Arrays.asList(2, 3);
		int count = blogMapper.deleteBlogList(ids);
		session.commit();
		session.close();
		System.out.println(count);
	}

6. 逆向工程

导入刚才的jar包和db.properties

作用:一键生成mapper和pojo

6.1 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:数据库的JDBC驱动的jar包地址 -->
	<classPathEntry location="D:\DX\CSDN\jar\c3p0\mysql-connector-java-8.0.11.jar" />
	<context id="DB2Tables" targetRuntime="MyBatis3">
		<commentGenerator>
			<!-- <property name="suppressAllComments" value="true" /> -->
			<property name="suppressDate" value="true" />
			<property name="javaFileEncoding" value="UTF-8" />
		</commentGenerator>
		<!-- 数据库链接URL、用户名、密码 -->
		<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
			connectionURL="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;serverTimezone=Hongkong&amp;characterEncoding=utf-8&amp;autoReconnect=true"
			userId="root" password="123">
		</jdbcConnection>
		<javaTypeResolver>
			<property name="forceBigDecimals" value="false" />
		</javaTypeResolver>
		<!--  生成model模型和位置pojo -->
		<javaModelGenerator targetPackage="cn.itcast.ssmIntegration.pojo"
			targetProject=".\src">
			<property name="enableSubPackages" value="false" />
			<property name="trimStrings" value="true" />
		</javaModelGenerator>
		<!-- 生成的SQL映射文件包名和位置mapper -->
		<sqlMapGenerator targetPackage="cn.itcast.ssmIntegration.mapper"
			targetProject=".\src">
			<property name="enableSubPackages" value="true" />
		</sqlMapGenerator>
		<!-- 生成DAO的包名和位置mapper接口,这里写 mapper-->
		<javaClientGenerator type="XMLMAPPER"
			targetPackage="cn.itcast.ssmIntegration.mapper" targetProject=".\src">
			<property name="enableSubPackages" value="true" />
		</javaClientGenerator>
		<!-- 指定表名 -->
		<table schema="" tableName="Blog"></table>
<!-- 		<table schema="" tableName="vehicle"></table> -->
	</context>
</generatorConfiguration>

6.2 实现类

public class Generator {
	public static void main(String[] args) throws Exception {
		List<String> warnings = new ArrayList<String>();
		boolean overwrite = true;
		File configFile = new File("generator.xml");
		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration config = cp.parseConfiguration(configFile);
		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
		myBatisGenerator.generate(null);
	}
}

运行并刷新

7. 逆向工程的使用与扩展

创建项目二,构建环境和目录结构,直接编写测试用例:

// 查询单项
	@Test
	public void testSelect() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Blog blog = blogMapper.selectByPrimaryKey(2);
		session.close();
		System.out.println(blog);
	}
	// 模糊多条件查询多项
	@Test
	public void testSelectExample() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);

		BlogExample blogExample = new BlogExample();
		BlogExample.Criteria blogCriteria = blogExample.createCriteria();
		blogCriteria.andTitleLike("%h%");
		blogCriteria.andStyleLike("black");
		List<Blog> blog = blogMapper.selectByExample(blogExample);
		session.close();
		System.out.println(blog);
	}

其他操作同理,但缺点是不支持多表查询

可以对其进行扩展进行连接查询:

新建cn.itcast.mybatis.vo及类BlogCustom实例:

public class BlogCustom extends Blog{
	private String authorUsername;

	public String getAuthorUsername() {
		return authorUsername;
	}

	public void setAuthorUsername(String authorUsername) {
		this.authorUsername = authorUsername;
	}

	@Override
	public String toString() {
		return "BlogCustom [authorUsername=" + authorUsername + ", getId()=" + getId() + ", getTitle()=" + getTitle()
				+ ", getAuthorid()=" + getAuthorid() + ", getState()=" + getState() + ", getFeatured()=" + getFeatured()
				+ ", getStyle()=" + getStyle() + "]";
	}
}

新建BlogMapperCustom.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="cn.itcast.mybatis.mapper.BlogMapperCustom">
	<sql id="baseColumn">
		b.`id`,
		b.`title`,
		b.`authorId`,
		b.`state`,
		b.`featured`,
		b.`style`,
		a.username as authorUsername
	</sql>
	<select id="selectBlogById" parameterType="int" resultType="BlogCustom">
		select
		<include refid="baseColumn"></include>
		from blog b left join author a on b.authorId=a.id
		where
		b.id=#{id}
	</select>
</mapper>

数据库表author实例:

create table `author` (
	`id` int (10),
	`username` varchar (150),
	`password` varchar (150),
	`email` varchar (150),
	`bio` varchar (150),
	`favouriteSection` varchar (150),
	`nickname` varchar (150),
	`realname` varchar (150)
); 
insert into `author` (`id`, `username`, `password`, `email`, `bio`, `favouriteSection`, `nickname`, `realname`) values('1','你好','123','123@qq.com','123','这个','Mick','ssm');
insert into `author` (`id`, `username`, `password`, `email`, `bio`, `favouriteSection`, `nickname`, `realname`) values('2','qwer','222','222@qq.com','234','nage','Bob','ssh');
insert into `author` (`id`, `username`, `password`, `email`, `bio`, `favouriteSection`, `nickname`, `realname`) values('3','so','123456','22@qq.com','234','nage','Lucy','struts');
insert into `author` (`id`, `username`, `password`, `email`, `bio`, `favouriteSection`, `nickname`, `realname`) values('4','bec','111','2@qq.com','234','age','Risk','sm');

接口BlogMapperCustom.java实例:

public interface BlogMapperCustom {
	BlogCustom selectBlogById(Integer id);
}

测试结果实例:

// 查询并查询出另一个表的名字
	@Test
	public void testSelectBlogById() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapperCustom blogMapper = session.getMapper(BlogMapperCustom.class);
		
		BlogCustom blog = blogMapper.selectBlogById(1);
		System.out.println(blog);
		session.close();
	}

项目二的文件目录:

8. 嵌套查询

8.1 一对一查询

新建项目三,在项目一(Blog)的基础上新增pojo类:

public class Author {
	private Integer id;
	private String username;
	private String password;
	private String email;
	private String bio;
	private String favouriteSection;
	private String nickname;
	private String realname;
//后面你懂的

blog改动如下:

	private Integer id;
	private String title;
//	private Integer authorId;
	private Author author;
	private String state;
	private Boolean featured;
	private String style;

BlogMapper.xml配置变更(<resultMap>的使用):

<resultMap type="Blog" id="blogResultMap">
		<id column="id" property="id" jdbcType="INTEGER" />
		<!-- association通常用来映射一对一的关系,这里把authorId作为author的id传过去实现链接查询 -->
		<association property="author" column="authorId" javaType="Author"
			select="cn.itcast.mybatis.mapper.AuthorMapper.selectAuthorById"></association>
</resultMap>
<select id="selectBlogById" parameterType="int" resultMap="blogResultMap">
	select * from blog where id=#{id}
</select>

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="cn.itcast.mybatis.mapper.AuthorMapper">
	<resultMap type="Author" id="authorResultMap">
		<id column="id" property="id" jdbcType="INTEGER"/>
	</resultMap>
	
	<select id="selectAuthorById" parameterType="int" resultMap="authorResultMap">
		select * from author where id = #{id}
	</select>
</mapper>

分别配置接口:

public interface AuthorMapper {
	Author selectAuthorById(Integer id);
}

public interface BlogMapper {
	Blog selectBlogById(Integer id);
}

测试用例:

@Test
public void testSelectBlog() {
	SqlSession session = MyBatisUtil.getSqlSession();
	BlogMapper blogMapper = session.getMapper(BlogMapper.class);
	Blog blog = blogMapper.selectBlogById(1);
	System.out.println(blog);
	session.close();
}

8.2 多对一查询

BlogMapper.xml配置增加

<select id="selectBlogList" resultMap="blogResultMap">
	select * from blog
</select>

BlogMapper接口新增:

List<Blog> selectBlogList();

测试用例:

	@Test
	public void testSelectBlogList() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		List<Blog> blog = blogMapper.selectBlogList();
		System.out.println(blog);
		session.close();
	}

8.3 嵌套结果查询

BlogMapper.xml配置新增:

<resultMap type="Blog" id="BlogResultMapNested">
		<id column="id" property="id" jdbcType="INTEGER"></id>
		<association column="blog_authorId" property="author"
			javaType="Author">
			<id column="author_id" property="id"></id>
		</association>
	</resultMap>
	<select id="selectBlogListNested" resultMap="BlogResultMapNested">
		SELECT
		b.id AS
		blog_id,
		b.title AS blog_title,
		b.authorId AS blog_authorId,
		b.state AS
		blog_state,
		b.featured AS blog_featured,
		b.style AS blog_style,

		a.id AS
		author_id,
		a.username AS author_username,
		a.password AS author_password,
		a.email AS author_email,
		a.bio AS author_bio,
		a.favouriteSection AS
		author_favouriteSection,
		a.nickname AS author_nickname,
		a.realname AS
		author_realname

		FROM blog b
		LEFT JOIN author a
		ON b.authorId=a.id
	</select>

配置接口之后

测试用例:

// 嵌套查询结果,1次select
	// 限制性关联查询,一次将所有数据查出来
	// 再将所有查询出来的列组织成嵌套的对象结果
	// 效率高
	@Test
	public void testSelectBlogListNested() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		List<Blog> blog = blogMapper.selectBlogListNested();
		System.out.println(blog);
		session.close();
	}

9. 缓存

9.1 一级缓存

观察上面项目三的第二个运行结果的sql语句,查出来7个结果,调用5次select语句,是由于一级缓存作用提高了效率

回到项目一中执行如下代码

	// 一级缓存默认存在
	// 第二次执行相同查询,第二次会从缓存中获取数据
	@Test
	public void testSelectBlogCachelevelOne1() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Blog blog = blogMapper.selectBlog(1);
		System.out.println("已查询");
		Blog blog1 = blogMapper.selectBlog(1);
		System.out.println("已查询,缓存中获取数据");
		session.close();
		System.out.println("session关闭");
	}

观察打印结果证实结论

修改表的操作会刷新缓存,可自行测试

9.2 二级缓存

开启二级缓存,BlogMapper.xml新增

<!-- 开启二级缓存 -->
<cache/>

pojo类要继承Serializable

测试用例:

//二级缓存默认不开启 在不同的session执行相同的查询 每次查询将会执行独立的数据检索过程
@Test
public void testSelectBlogCachelevelTwo2() {
    SqlSession session = MyBatisUtil.getSqlSession();
    BlogMapper blogMapper = session.getMapper(BlogMapper.class);
    Blog blog = blogMapper.selectBlog(1);
    System.out.println("已查询");
    session.close();
    SqlSession session1 = MyBatisUtil.getSqlSession();
    BlogMapper blogMapper1 = session1.getMapper(BlogMapper.class);
    Blog blog1 = blogMapper1.selectBlog(1);
    System.out.println("已查询,缓存中获取数据");
    session1.close();
    System.out.println("session关闭");
}

可以观察未开启与开启后的不同

一般对查询频率高,变化频率低的数据建议使用二级缓存

二级缓存虽然提高了效率,但也带来了危害,详情百度

10. 鉴别器

回到项目三,创建pojo类

public class Vehicle {
	private Integer id;
	private String vin;
	private String year;
	private String make;
	private String model;
	private String color;

新建数据库表:

create table `vehicle` (
	`id` int (10),
	`vin` varchar (30),
	`year` year (4),
	`make` varchar (60),
	`model` varchar (60),
	`color` varchar (60),
	`vehicleType` int (20),
	`doorCount` int (20),
	`allWheelDrive` tinyint (1)
); 
insert into `vehicle` (`id`, `vin`, `year`, `make`, `model`, `color`, `vehicleType`, `doorCount`, `allWheelDrive`) values('1','AA','2010','VOLVO','S80','黑','1','4',NULL);
insert into `vehicle` (`id`, `vin`, `year`, `make`, `model`, `color`, `vehicleType`, `doorCount`, `allWheelDrive`) values('2','VB','2008','SUN','S600','红','1','4',NULL);
insert into `vehicle` (`id`, `vin`, `year`, `make`, `model`, `color`, `vehicleType`, `doorCount`, `allWheelDrive`) values('3','CC','2011','宝马','X6','绿','2',NULL,'1');
insert into `vehicle` (`id`, `vin`, `year`, `make`, `model`, `color`, `vehicleType`, `doorCount`, `allWheelDrive`) values('4','DD','2014','路虎','发现4','红','2',NULL,'0');

观察表数据,我们的目的是根据vehicleType的不同值查询不同的结果

VehicleMapper.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="cn.itcast.mybatis.mapper.VehicleMapper">
	<resultMap type="Vehicle" id="vehicleResultMap">
		<id column="id" property="id" jdbcType="INTEGER" />
		<!-- 配置鉴别器 -->
		<discriminator javaType="int" column="vehicleType">
			<case value="1" resultType="Car">
				<result column="doorCount" property="doorCount"/>
			</case>
			<case value="2" resultType="Suv">
				<result column="allWheelDrive" property="allWheelDrive"/>
			</case>
		</discriminator>
	</resultMap>

	<select id="selectVehicleById" resultMap="vehicleResultMap"
		parameterType="int">
		select * from vehicle where id=#{id}
	</select>
</mapper>

配置接口,然后测试用例:

@Test
public void testSelectVehicleById() {
	SqlSession session = MyBatisUtil.getSqlSession();
	VehicleMapper vehicleMapper = session.getMapper(VehicleMapper.class);
	Vehicle vehicle = vehicleMapper.selectVehicleById(1);
	Vehicle vehicle1 = vehicleMapper.selectVehicleById(3);
	System.out.println(vehicle);
	System.out.println(vehicle1);
	session.close();
}

11. 加载类型

在mybatis-config.xml中添加配置

<settings>
	<!-- 配置延迟加载 -->
	<setting name="lazyLoadingEnabled" value="true" />
	<!-- 非积极的延迟加载 -->
	<setting name="aggressiveLazyLoading" value="false" />
</settings>

第二条不配值默认为false

观察测试用例:

	/**
	 * 延迟加载
	 * 虽然只要求查询blog,但执行了select * from author where id = ?
	 * 影响效率
	 * 在mybatis-config.xml中配置延迟加载消除影响
	 * 但是默认是积极加载,所以查询blog的任意属性,还是会查到author
	 * 再配置非积极加载,达到最高效率
	 */
	@Test
	public void testSelectBlogByIdLazyLoading() {
		SqlSession session = MyBatisUtil.getSqlSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		System.out.println("查询Blog");
		Blog blog = blogMapper.selectBlogById(1);
		session.close();
		System.out.println("查询Blog的title");
		System.out.println(blog.getTitle());
//		System.out.println("查询Blog的author");
//		System.out.println(blog.getAuthor().getUsername());
//		System.out.println("查询结束");
	}

到这里mybatis的入门总结算是完成了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值