MyBatis框架-应用篇(2)

  1. 动态SQL语句

    (1) Xml方式

    (2) 注解方式

  2. MyBatis的缓存

  3. MyBatis的关联查询

  4. MyBatis逆向工程

1. 动态SQL语句

1.1. 动态SQL是什么

就是相对与固定SQL。就是通过传入的参数不一样,可以组成不同结构的SQL语句. 这种根据参数的条件修改SQL结构的SQL语句,我们称为动态SQL语句.

1.2. 动态SQL有什么用

1.根据条件组装不同结构的SQL语句,可以提高SQL代码的重用性.

2.满足某些特定需求,如,条件判断查询

1.3. 基于XML的实现

1.3.1. 标签包括

用于声明公有的SQL语句块.,在操作标签中使用调用 [不建议用]

不建议的原因,会导致代码难以维护。

类似java if(){},用于判断

:类似java的foreach循环,一般用户批量处理的SQL语句

:切割标签,主要用于切割关键字的头和尾的字符.新版的Mybatis使用的几率很少.

:使用 set标签就是SQL语言的set关键字,可以在update 的时候set 关键字后面的,逗号可以自动忽略

:使用where标签作为SQL语言的where关键字,好处如果where后面的条件都不成立,忽略where关键字.

: java的swithc case

1.3.2. 接口文件

package cn.zj.mybatis.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import cn.zj.mybatis.pojo.User;

public interface UserMapper {
	
	/**
	 * 根据条件查询结果
	 * @param user
	 * @return
	 */
	List<User> selectByCondition(User user);
	
	/**
	 * 根据提交查询总数
	 * @param user
	 * @return
	 */
	Long selectTotalByCondition(User user);
	
	/**
	 * 修改用户
	 * @param user
	 * @return
	 */
	int updateUserByNotNull(User user);
	
	/**
	 * 批量删除用户
	 * @param ids
	 * @return
	 */
	int deleteByIds(@Param("ids")Integer[] ids);
	
	/**
	 * 批量插入
	 * @param users
	 * @return
	 */
	int insertByBatch(@Param("users")List<User> users);
	
}

1.3.3. 映射文件

<?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 配置 mybatis 表的映射
	namespache :命名空间(和对应映射的接口的 全限定名一样),通俗讲,当前映射文件的唯一标识
		全限定名 : 包名+接口名/类名
 --> 
<mapper namespace="cn.zj.mybatis.mapper.UserMapper">

	
	<!-- sql片段 -->
	<sql id="condition_sql">
		<!-- where 标签 -->
		<where>
			<if test="name !=null">
				name like  concat('%',#{name},'%')
			</if>
			<if test="password !=null">
				and password = #{password}
			</if>
			<if test="age !=null">
				and age = #{age}
			</if>
		</where>
		
	</sql>
	
	<!-- 多条件查询 -->
	<select id="selectByCondition" parameterType="cn.zj.mybatis.pojo.User" resultType="cn.zj.mybatis.pojo.User">
		select * from user 
		<!-- 引入sql片段 -->
		<include refid="condition_sql"/>
	</select>
	
	<!-- 多条件查询总数 -->
	<select id="selectTotalByCondition" parameterType="cn.zj.mybatis.pojo.User" resultType="long">
		select count(*) from user 
		<!-- where 标签 -->
		<include refid="condition_sql"/>
	</select>
	
	<!-- 修改用户信息(数据不为空的修改) -->
	<update id="updateUserByNotNull" parameterType="cn.zj.mybatis.pojo.User">
		update user 
		<set>
			<if test="name !=null">
				name = #{name},
			</if>
			<if test="password !=null">
				password = #{password},
			</if>
			<if test="age !=null">
				age = #{age},
			</if>
		</set>
		where id = #{id}
	</update>
	
	<!-- 批量删除 -->
	<delete id="deleteByIds" parameterType="integer">
		<!-- sql : delete from user where id in (1,2,3,4) -->
		delete from user where id in 
		
		<!-- 动态sql语句值 foreach -->
		
		<foreach collection="ids" item="id" open="(" close=")" separator=",">
			#{id}
		</foreach>
	</delete>
	
	<!-- 批量插入 -->	
	<delete id="insertByBatch" parameterType="list">
		<!-- insert into user (name,password,age) values (xx,xx,xx),(xx1,xx1,xx1) -->
		
		insert into user (name,password,age) values
		
		<foreach collection="users" item="user" separator="," >
			(#{user.name},#{user.password},#{user.age})
		</foreach>
	</delete>
</mapper>

1.3.4. 测试代码

package cn.zj.mybatis.test;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import cn.zj.mybatis.mapper.UserMapper;
import cn.zj.mybatis.pojo.User;
import cn.zj.mybatis.util.MyBatisUtil;

public class UserMapperTest {

	@Test
	public void testSelectByCondition() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();

		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);

		User user = new User();
		// user.setAge(30);
		user.setName("哥");
		List<User> users = userMapper.selectByCondition(user);
		for (User user2 : users) {
			System.out.println(user2);
		}
		
		Long totalCount = userMapper.selectTotalByCondition(user);
		System.out.println(totalCount);
		
		//关闭sesison
		session.close();
	}

	@Test
	public void testInsert() throws Exception {

		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();

		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);
		User user1 = new User(null, "西门吹雪", "xmcx", 25);
		User user2 = new User(null, "东方不败", "dfbb", 30);

		List<User> users = new ArrayList<>();
		
		users.add(user1);
		users.add(user2);
		// 3. 执行UserMapper的批量插入方法
		int row = userMapper.insertByBatch(users);
		System.out.println(row);
		
		
		// 4.提交事务(MyBatis是手动提交事务)
		session.commit();

		// 5.关闭Session
		session.close();
	}


	@Test
	public void testUpdate() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);

		User user = new User(1, null, "xf", null);
		// 3.执行修改方法
		int row = userMapper.updateUserByNotNull(user);
		System.out.println(row);
		// 4.提交事务
		session.commit();

		// 5.关闭session
		session.close();
	}

	@Test
	public void testDelete() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);

		Integer[] ids = { 2, 3, 5 };

		// 3.执行修改方法
		int row = userMapper.deleteByIds(ids);
		System.out.println(row);
		// 4.提交事务
		session.commit();

		// 5.关闭session
		session.close();
	}

}

1.4. 基于注解方式实现

动态sql除了支持xml方式以外,还是支持使用纯注解的方式

主要一下四个注解+对应动态sql语句的类文件

1. *@SelectProvider* 动态查询SQL语句对应注解

2. *@InsertProvider* 动态插入SQL语句对应注解

3. *@UpdateProvider* 动态修改SQL语句对应注解

4. *@DeleteProvider* 动态删除SQL语句对应注解

1.4.1. 接口映射文件

package cn.zj.mybatis.mapper;

import java.util.List;

import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;

import cn.zj.mybatis.pojo.User;
import cn.zj.mybatis.pojo.UserProvider;

public interface UserMapper {
	
	
	/*
	 * @SelectProvider(type=UserProvider.class,method="")
	 * @SelectProvider 查询动态sql语句的 注解
	 * type : 编写动态sql语句的类对应的字节码
	 * method : 编写动态sql语句类对应的方法名称
	 * 	此方法返回的是一个String字符串,字符串就是拼接sql语句
	 */
	@SelectProvider(type=UserProvider.class,method="selectByCondition")
	List<User> selectByCondition(User user);
	
	/**
	 * 根据条件查询总数
	 * @param user
	 * @return
	 */
	@SelectProvider(type=UserProvider.class,method="selectTotalByCondition")
	Long selectTotalByCondition(User user);
	
	
	/**
	 * 修改用户信息,参数不为空的数据才会修改
	 * @param user
	 * @return
	 */
	@UpdateProvider(type=UserProvider.class,method="updateByNotNull")
	int updateByNotNull(User user);
	
	
	/**
	 * 批量删除
	 * @param ids
	 * @return
	 */
	@DeleteProvider(type=UserProvider.class,method="deleteByIds")
	int deleteByIds(@Param("ids")List<Integer> ids);
	
	/**
	 * 批量插入
	 * @param users
	 * @return
	 */
	@InsertProvider(type=UserProvider.class,method="batchInsert")
	int batchInsert(@Param("users")List<User> users);
}

1.4.2. 动态sql语句文件

package cn.zj.mybatis.pojo;

import java.util.List;

import org.apache.ibatis.annotations.Param;

/*
 * UserMapper接口映射对应的动态SQL语句的的类
 */
public class UserProvider {
	
	/**
	 * 返回条件查询对应的动态sql语句
	 * @param user  条件参数
	 * @return sql
	 */
	public String selectByCondition(User user) {
		StringBuilder sb = new StringBuilder();
		sb.append("select * from user WHERE 1 = 1 ");
		//动态拼接SQL语句
		if(user.getName() !=null) {
			//使用OGNL表达式获取 对象属性的值
			sb.append("AND name like  concat('%',#{name},'%')");
		}
		if(user.getAge() !=null) {
			sb.append("AND age = #{age}");
		}
		
		return sb.toString();
	}
	
	public String selectTotalByCondition(User user) {
		StringBuilder sb = new StringBuilder();
		sb.append("select count(1) from user WHERE 1 = 1 ");
		//动态拼接SQL语句
		if(user.getName() !=null) {
			//使用OGNL表达式获取 对象属性的值
			sb.append("AND name like  concat('%',#{name},'%')");
		}
		if(user.getAge() !=null) {
			sb.append("AND age = #{age}");
		}
		
		return sb.toString();
	}
	
	
	
	public String updateByNotNull(User user) {
		StringBuilder sb = new StringBuilder();
		sb.append("update user set ");
		
		if(user.getName() !=null) {
			sb.append("name = #{name},");
		}
		if(user.getPassword() !=null) {
			sb.append("password = #{password},");
		}
		if(user.getAge() !=null) {
			sb.append("age = #{age},");
		}
		//删除最后一个多余的逗号
		sb.deleteCharAt(sb.length()-1);
		
		sb.append(" where id = #{id}");
		
		return sb.toString();
	}
	
	
	public String deleteByIds(@Param("ids")List<Integer> ids) {
		StringBuilder sb = new StringBuilder();
		//delete from user where id in (1,3,5,6);
		sb.append("delete from user where id in (");
		
		for (int i = 0; i < ids.size(); i++) {
			//使用OGNL 表达式获取集合的每一个数据  #{ids[0]} #{ids[1]} #{ids[2]}...
			sb.append("#{ids["+i+"]},");
		}
		
		//删除最后一个多余的逗号
		sb.deleteCharAt(sb.length()-1);
		
		sb.append(")");
		return sb.toString();
	}
	
	public String batchInsert(@Param("users")List<User> users) {
		StringBuilder sb = new StringBuilder();
//		insert into user (name,password,age) values
//			(xxx,x,xx),(xxx1,x1,xx1),(xxx2,x2,xx2),
		sb.append("insert into user (name,password,age) values ");
		
		for (int i = 0; i < users.size(); i++) {
			sb.append("(");
			//姓名
			sb.append("#{users["+i+"].name},");
			//密码
			sb.append("#{users["+i+"].password},");
			//年龄
			sb.append("#{users["+i+"].age}");
			sb.append("),");
		}
		//删除最后一个多余的逗号
		sb.deleteCharAt(sb.length()-1);
		System.out.println("SQL :"+sb.toString());
		return sb.toString();
	}
}

1.4.3. 测试代码

package cn.zj.mybatis.test;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import cn.zj.mybatis.mapper.UserMapper;
import cn.zj.mybatis.pojo.User;
import cn.zj.mybatis.util.MyBatisUtil;

public class UserMapperTest {

	@Test
	public void testSelectByCondition() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();

		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);

		User user = new User();
		// user.setAge(30);
		user.setName("哥");
		List<User> users = userMapper.selectByCondition(user);
		for (User user2 : users) {
			System.out.println(user2);
		}
// 查询总数
		Long totalCount = userMapper.selectTotalByCondition(conditionUser);
		System.out.println("totalCount:" + totalCount);
		// 关闭session
		session.close();
	}

	@Test
	public void testInsert() throws Exception {

		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();

		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);
		User user1 = new User(null, "西门吹雪", "xmcx", 25);
		User user2 = new User(null, "东方不败", "dfbb", 30);

		List<User> users = new ArrayList<>();
		
		users.add(user1);
		users.add(user2);
		// 3. 执行UserMapper的批量插入方法
		int row = userMapper.insertByBatch(users);
		System.out.println(row);
		
		
		// 4.提交事务(MyBatis是手动提交事务)
		session.commit();

		// 5.关闭Session
		session.close();
	}

	@Test
	public void testUpdate() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);

		User user = new User(5, null, "xf", null);
		// 3.执行修改方法
		int row = userMapper.updateUserByNotNull(user);
		System.out.println(row);
		// 4.提交事务
		session.commit();

		// 5.关闭session
		session.close();
	}

	@Test
	public void testDelete() throws Exception {
		// 1.创建SqlSession对象
		SqlSession session = MyBatisUtil.openSession();
		// 2.创建UserMapper接口的代理对象
		UserMapper userMapper = session.getMapper(UserMapper.class);

		Integer[] ids = { 2, 3, 5 };

		// 3.执行修改方法
		int row = userMapper.deleteByIds(ids);
		System.out.println(row);
		// 4.提交事务
		session.commit();

		// 5.关闭session
		session.close();
	}
}

2. 缓存

在Mybatis里面,所谓的缓存就是将已经查询过的记录放在内存的缓冲区或文件上,这样如果再次查询,可以通过配置的策略,命中已经查询过的记录.从而提高查询的效率.

缓存作用

提高查询的效率.

2.1. 一级缓存

Mybatis的缓存分为一级缓存\ 二级缓存

一级缓存:所谓的一级缓存就是会话(SqlSesion对象)级别的缓存,就是同一个会话,如果已经查询过的数据会保存一份在内存中,如果会话没有关闭,再次调用同样的方法查询,不会再查询数据库,而是直接从缓存中取出之前查询的数据.

一级缓存默认是打开的,而且是关闭不了的.

如何清空一级缓存.

1.关闭会话.close()

2.进行了操作(增删改),提交了commit();

3.手工清除缓存clearCache()

2.1.1. 测试代码

@Test
public void testselectAll() {
	// 1.创建SqlSession对象
	//SqlSesion对象默认就开启了一级缓存,将已经查询过的数据就缓存到SqlSession的缓存区域
	//在此会话中如果再次发送同样的请求,那么直接从缓存区域获取数据,不会再发送SQL语句了
	
	SqlSession session1 = MyBatisUtil.openSession();
	//SqlSession session2 = MyBatisUtil.openSession();
	// 2.创建UserMapper接口的代理对象
	UserMapper mapper1 = session1.getMapper(UserMapper.class);
	
	//UserMapper mapper2 = session2.getMapper(UserMapper.class);
	//3.执行查询方法
	List<User> users1 = mapper1.selectAll();
	
	//手动清理缓存
	session1.clearCache();
	
	List<User> users2 = mapper1.selectAll();
}

2.2. 二级缓存

一级缓存是SqlSession对象级别,在每一次会话中有效

二级缓存是 ****SqlSessionFactory****级别,在整个应用都有效,可以在多个会话有效

MyBatis本身并没有实现二级缓存

二级缓存需要第三方缓存提供商的支持

Ehcache -第三方缓存(Hibernate框架默认就是支持)

学习地址

http://www.mybatis.org/ehcache-cache/

2.2.1. 下载ehcache

https://github.com/mybatis/ehcache-cache/releases

2.2.2. 配置开启二级缓存

MyBatis开启二级缓存新版本已经默认支持开启二级缓存.可以不改

<settings>	
    <!-- 开启二级缓存 -->
    <setting name=*"cacheEnabled" value="true"/>
</settings>

2.2.3. 导入Ehcachejar包

在这里插入图片描述

2.2.4. Ehcache依赖 slfj 日志框架,必须要导入slfj的两个jar包

在这里插入图片描述

2.2.5. 创建 ehcache.xml配置文件

Ehcache有自己的配置文件,在src下面创建ehcache.xml 配置文件

<ehcache>
	<!-- 缓存的磁盘位置 -->
	<diskStore path="D:/mybatis_cache"/>
	<!-- 默认的缓存策略: 如果开发者在某一个需要缓存的文件配置了自定义缓存,就不使用默认的,如果没有配置,就使用默认缓存策略-->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
      />
</ehcache>

在映射文件中配置以及配置对应的缓存策略

<mapper namespace="cn.zj.mybatis.dao.UserMapper">
	
	<!-- 当前表的映射开启支持二级缓存,并设置相关的缓存提供商,以及缓存的相关配置 -->
	<cache type="org.mybatis.caches.ehcache.EhcacheCache" >
       <!--最大的空闲时间  -->
       <property name="timeToIdleSeconds" value="10000"/>
       <!-- 最大的在线时间 -->
       <property name="timeToLiveSeconds" value="20000"/>
       <!-- 内存的大小 b字节 m1 =1024k 1k=1024b -->
       <property name="maxEntriesLocalHeap" value="2000000"/>
       <!-- 文件的大小 b字节-->
       <property name="maxEntriesLocalDisk" value="20000000"/>
       <!-- 算法 LRU:最少使用优先, "LFU" or "FIFO:先进先出 -->
       <property name="memoryStoreEvictionPolicy" value="LRU"/>
    </cache> 
	<select id="selectAll" resultType="User">
		select * from user
	</select>
</mapper>

因为二级缓存可以缓存到文件(将对象序列化到本地),涉及到对象序列化,那么对应的javaBean对象就必须实现

public class User implements Serializable{
	private static final long serialVersionUID = -8366151150155170110L;
}

2.2.6. 缓存的命中率

命中率= 从缓存中获取数据的次数/ 查询的总次数

如 : 两次查询 从缓中获取一次

0.5 = 1/2;

0.666666 = 2/3;

命中率越高缓存效果越好

缓存结果如下

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.0

DEBUG [main] - ==> Preparing: select * from user where id = ?

DEBUG [main] - ==> Parameters: 3(Integer)

DEBUG [main] - <== Total: 1

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.5

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.6666666666666666

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.75

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8333333333333334

DEBUG [main] - Cache Hit Ratio [cn.zj.mybatis.mapper.UserMapper]: 0.8571428571428571

3. MyBatis的对象关系映射(难点重点)

在实际开发中,一个业务可能涉及到多个数据表的查询,那么多表查询就涉及连接查询(等值连接), 等值连接 表与表之间有一个外键关键

但是程序中最终获取的表封装的对象, *对象与对象之间是没有外键关系的,********对象和对象之间只有依赖关系*

对象之间关系主要是四种

*一对一 关系*
一个人对应身份证id,一个QQ号对应一个QQ空间

*一对多 关系*

一个部门对应多个员工

*多对一 关系*

多个员工对应一个部门

*多对多 关系*

多个学生对应多个老师,多个学生对应多个课程

什么关系应该从哪个对象作为中心点来看

一对多, 以one方作为中心点

MyBatis框架支持多表查询封装对象之间关系

一对多查询

多对一和一对一查询

3.1. 准备多表,表之间有外键关系(员工表和部门表)

员工表
CREATE TABLE `employee` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
部门表
CREATE TABLE `department` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

3.2. 多对一查询

pojo对象以及映射关系

public class Employee {
	private Integer id;
	private String name;
	//以员工为中心 : 
                      多个员工对应一个部门,多对一关系,many2one
	//员工与部门的对象关系
	private Department dept;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Department getDept() {
		return dept;
	}

	public void setDept(Department dept) {
		this.dept = dept;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", dept=" + dept + "]";
	}
}
public class Department {
	private Integer id;
	private String name;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Department [id=" + id + ", name=" + name + "]";
	}
}

Man2oneMapper.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">
 <!-- 映射配置
 	namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称
  -->
<mapper namespace="cn.zj.mybatis.mapper.Many2OneMapper">


	<select id="selectByEmpId" parameterType="Integer" resultMap="emp_map">
		
		select * from employee where id = #{id}
		
	</select>
	
	
	<resultMap type="cn.zj.mybatis.pojo.Employee" id="emp_map">
		
		<id column="id" property="id"/>
		<result column="name" property="name"/>	
		
		<!-- 
		    需要映射部门对象属性
			private Department dept;
			
		   解决方案,使用关联查询
		   <association property="dept" column="dept_id" select=""/>
		   	property :需要映射的属性
		   	column :要映射属性对应的外键列
		   	select :对应的查询方案, 对应查询的命名空间+.+功能id
		 -->
		<association property="dept" column="dept_id" 
		select="cn.zj.mybatis.mapper.Many2OneMapper.findDeptById"/>
		
	</resultMap>
	
	<!-- 根据部门Id查询对应的部门对象 -->
	<select id="findDeptById" parameterType="Integer" resultType="cn.zj.mybatis.pojo.Department">
		select * from department where id = #{dept_id}
	</select>
	
</mapper>

3.3. 一对多查询

以部门为中心查询部门的所有信息(包括员工),一个部门对应多个员工

pojo对象以及映射关系

public class Department {
	private Integer id;
	private String name;
	
	//以部门为中心:一个部门对应多个与员工  一对多关系 (one2many)
	private List<Employee> emps;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public List<Employee> getEmps() {
		return emps;
	}
	public void setEmps(List<Employee> emps) {
		this.emps = emps;
	}
	@Override
	public String toString() {
		return "Department [id=" + id + ", name=" + name + ", emps=" + emps + "]";
	}
}
public class Employee {
	private Integer id;
	private String name;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + "]";
	}
}

3.3.1. N+1方式

N+1 : N 就是当前需要查询结果对应发送的SQL语句的条数

​ +1 关联查询数据需要额外多发一条SQL语句才能查询出对应的结果

3.3.1.1. 映射代码
<?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">
 <!-- 映射配置
 	namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称
  -->
<mapper namespace="cn.zj.mybatis.mapper.One2ManyMapper">
	<select id="selectDeptById" parameterType="Integer" resultMap="dept_map">	
		select * from department where id = #{id}
	</select>
	
	<!-- 手动映射 -->
	<resultMap type="cn.zj.mybatis.pojo.Department" id="dept_map">
		<id column="id" property="id"/>
		<result column="name" property="name"/>
		
		<!-- private List<Employee> emps;
			集合属性映射
			 <collection property="emps" column="id" select=""/>
			 	property:需要映射得集合 emps
			 	column : 部门的主键 id
			 	select : 关联查询,去根据部门id查询出对应的员工
			 			 值关联查询功能的  命名空间+.+功能id
		 -->
		 <collection property="emps" column="id" select="cn.zj.mybatis.mapper.One2ManyMapper.selectUsersByDeptId"/>
	
	</resultMap>
	
	
	<!-- 关联查询的功能
		根据部门的id查询所有的员工
	 -->
	<select id="selectUsersByDeptId" parameterType="integer" resultType="cn.zj.mybatis.pojo.Employee">
		select * from employee where dept_id = #{id}
	</select>
</mapper>
3.3.1.2. 运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5gk7nEPX-1623487509905)(file:///C:\Users\86198\AppData\Local\Temp\ksohtml9124\wps3.jpg)]

3.3.2. 等值连接查询

3.3.2.1. 映射代码
<?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">
 <!-- 映射配置
 	namespace : 命名空间,通俗讲,每个映射文件唯一的标识名称
  -->
<mapper namespace="cn.zj.mybatis.mapper.One2ManyMapper">


	<select id="selectDeptById" parameterType="Integer" resultMap="dept_map">
		
		select e.id e_id ,e.name e_name,d.id d_id,d.name d_name
	from department d JOIN employee e ON d.id = e.dept_id WHERE d.id = #{id};
		
	</select>
	
	<!-- 手动映射 -->
	<resultMap type="Department" id="dept_map">
		<id column="d_id" property="id"/>
		<result column="d_name" property="name"/>
		
		<!-- private List<Employee> emps;
			集合属性映射
			 <collection property="emps" column="id" select=""/>
			 	property:需要映射得集合 emps
			 	column : 部门的主键 id
			 	ofType : 需要映射集合的泛型的类型
		 -->
		 
		 <collection property="emps" ofType="Employee">
		 	<!-- 集合泛型类型对应的pojo的主键列映射 ,Employee的主键列映射 -->
		 	<id column="e_id" property="id"/>
		 	<!-- 集合泛型类型对应的pojo的非主键列映射 ,Employee的非主键列映射 -->
		 	<result column="e_name" property="name"/>
		 </collection>
	
	</resultMap>
	
</mapper>
3.3.2.2. 运行结果

只会发送一条SQL语句

DEBUG [main] - ==> Preparing: select e.id e_id ,e.name e_name,d.id d_id,d.name d_name from department d JOIN employee e ON d.id = e.dept_id WHERE d.id = ?;

DEBUG [main] - ==> Parameters: 1(Integer)

DEBUG [main] - <== Total: 2

Department [id=1, name=总经办, emps=[Employee [id=1, name=乔峰], Employee [id=3, name=段誉]]]

4. MyBatis的逆向工程

MyBatis的逆向工程能自动帮开发者生成数据库表对应的 pojo实体文件,自动生成映射文件自定生成表的各种(CRUD)的sql语句, 但是只能做单表操作,联合查询还得开发者自己动 使用逆向工程得先在Eclipse安装逆向工程的插件

4.1. 插件安装步骤

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

判断是否安装成功

在这里插入图片描述

4.2. 逆向工程步骤

4.2.1. 新建一个普通****java项目,导入mybatis.jar包和数据库驱动包

在这里插入图片描述

4.2.2. 生成配置文件

在这里插入图片描述

配置生成文件

<?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>
  <context id="context1">
   <!-- 注释构建 -->
    <commentGenerator>
       <!-- 去掉所有的注释 -->
    	<property name="suppressAllComments" value="true"/>
    	<property name="suppressDate" value="true"/>
    </commentGenerator>
    
    <!-- 数据库四要素 -->
    <jdbcConnection connectionURL="jdbc:mysql://localhost:3306/mybatis" 
    driverClass="com.mysql.jdbc.Driver" 
    password="admin" 
    userId="root" />
    <!-- 实体类 : pojo
    	targetPackage : 实体类生成后存放的包
    	targetProject : 存放的目录一般都放在 src下面
      -->
    <javaModelGenerator targetPackage="cn.zj.mybatis.pojo" targetProject="mybatis-generator/src" />
    <!-- 映射文件 -->
    <sqlMapGenerator targetPackage="cn.zj.mybatis.mapper" targetProject="mybatis-generator/src" />
    <!-- 操作接口 
    	type 生成映射的形式
    		ANNOTATEDMAPPER : 纯注解的,没有xml映射
    		XMLMAPPER : 生成的有xml映射文件
    -->
    <javaClientGenerator  targetPackage="cn.zj.mybatis.mapper" targetProject="mybatis-generator/src" type="XMLMAPPER" />
    
    <!-- 要生成对应表的配置
    	tableName : 数据库表名
    	//如果下面全部是true,mybatis直接可以使用纯面向对象开发
    	enableCountByExample : 是否生成查询总数的 Example 
    	enableDeleteByExample : 是否生成删除的 Example 
    	enableSelectByExample : 是否生成查询集合的 Example 
    	enableUpdateByExample : 是否生成修改的 Example 
     -->
    <table  tableName="user"  enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
    <table  tableName="employee" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
    <table  tableName="department" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="true" enableUpdateByExample="false"></table>
  </context>
</generatorConfiguration>

4.2.3. 开始逆向工程

选中 generatorConfig.xml 逆向工程配置文件,点击鼠标右键
在这里插入图片描述

4.3. 逆向功能的缺点

逆向功能不能逆向多表,只能逆向单表操作,多表之间有外键对应java关联关系没办法映射,需要开发者手动编写对应代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值