MyBatis学习总结大全:
- MyBatis学习总结第一天
- MyBatis学习总结第二天
- MyBatis学习总结第三天
今日大纲:
- < resultMap> 使用
- 多表查询四种方式
一对一
一对多
多对多
自关联 - MyBatis注解开发
- MyBatis 运行原理
多表操作
多表操作,当两个表中的字段名称一致,使用一次查询的时候,数据会混乱,所以在这种情况下,需要在写sql语句的时候,就将重复的字段进行别名设置,然后在resultMap中的column属性中的值为别名。
< resultMap>返回值集合
设计数据库的时候,不是所有数据库字段跟对象属性的命名规则一致。
userName ->USER_NAME
第一种:使用数据库别名关键字
第二种:< resultMap>标签
<mapper namespace="com.bjsxt.mapper.CardMapper">
<!--
定义的返回值集合
type:为返回值类型
id:在一个映射文件中的是唯一值
-->
<resultMap type="card" id="getCards">
<!-- 对应的是数据库表的主键 -->
<id column="card_id" property="cardId"/>
<!-- 对应的是数据除主键外的所有字段 -->
<result column="card_name" property="cardName"/>
</resultMap>
<!-- extends:可以继承已有的 resultMap,类似于Java的继承,可以使用父resultMap的定义的属性-->
<resultMap type="card" id="cards" extends="getCards">
<result column="card_no" property="cardNo"/>
<result column="user_id" property="userId"/>
</resultMap>
<!--
id:必要信息,在一个映射文件中,要保证唯一
resultType:如果使用resultMap,就省略,因为在resultMap已经定义返回类型
resultMap:返回值集合,它的值为已定义的<resultMap>标签的id值对应
-->
<select id="findCards" resultMap="cards">
select * from t_card
</select>
<!-- 第一种方式:使用别名解决数据库表字段与对象属性不一致问题 -->
<select id="getCards" resultType="card">
select
card_id as cardId,
card_name as cardName,
card_no as cardNo,
user_id as userId
from t_card
</select>
</mapper>
接口
public interface CardMapper {
List<Card> getCards();
List<Card> findCards();
}
测试
/**
*
* @Description: 别名查询
* @author mao
* @date 2017年10月12日
*/
@Test
public void getCards(){
CardMapper mapper = session.getMapper(CardMapper.class);
List<Card> cards = mapper.getCards();
for (Card card : cards) {
System.out.println(card);
}
}
/**
*
* @Description: 使用resultMap
* @author mao
* @date 2017年10月12日
*/
@Test
public void findCards(){
CardMapper mapper = session.getMapper(CardMapper.class);
List<Card> findCards = mapper.findCards();
for (Card card : findCards) {
System.out.println(card);
}
}
一对一
数据库的表的一对一关系在mybatis中怎么应用。一个用户只有一个身份证:
T_user 用户表
T_card 身份证表,我将用户的id作为外键保存身份证表中
--一对一查询的sql,两种方式
select t.*,c.* from t_user t,t_card c where t.id = c.USER_ID;
select * from t_card ;
select * from t_user where id=2;
1.在card对象中,创建用户的对象,构建他们的关系
2.在映射文件中构建card与用户表对应及查询关系
CardMapper.xml
<mapper namespace="com.bjsxt.mapper.CardMapper">
<resultMap type="card" id="card">
<id column="card_id" property="cardId"/>
<result column="card_name" property="cardName"/>
<result column="card_no" property="cardNo"/>
<result column="user_id" property="userId"/>
</resultMap>
<resultMap type="card" id="cards" extends="card">
<!-- 处理关联的一对一对象
property:对应的是关联对象的属性名称
javaType:对应的是关联对象的类型
resultMap:如果,该resultMap在同一个映射文件中,直接使用resultMap的id值
如果,不在同一个映射文件中,使用:namespace.resultMap的id
-->
<association property="user" javaType="user"
resultMap="com.bjsxt.mapper.UserMapper.users">
</association>
</resultMap>
<!-- 第一种:处理一对一的数据关联 ,一次查询-->
<select id="getCards" resultMap="cards">
select u.*,c.* from t_user u,t_card c where u.id = c.user_id
</select>
<resultMap type="card" id="card2" extends="card">
<!--
select:对应的是关联查询的select语句,值为select标签的id值
如果,查询select语句在同一个映射文件中,直接使用其id值
如果不在,使用select语句的,namespace.select的id值
column:放置外键,对应查询目标表的主键
-->
<association property="user" javaType="user"
select="com.bjsxt.mapper.UserMapper.getUsersById" column="user_id">
</association>
</resultMap>
<!--第二种方式:n+1查询 -->
<select id="getCards2" resultMap="card2">
select * from t_card
</select>
</mapper>
UserMapper.xml
<mapper namespace="com.bjsxt.mapper.UserMapper">
<resultMap type="user" id="users">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="pwd"/>
<result column="age" property="age"/>
</resultMap>
<!-- 接收参数的id :随便写 -->
<select id="getUsersById" resultMap="users">
select * from t_user where id=#{id}
</select>
<select id="getUsers" resultType="user">
select * from t_user
<where>
<if test="name != null and name != ''">
and name = #{name}
</if>
<choose>
<when test="pwd != null and pwd != ''">
and pwd = #{pwd}
</when>
<otherwise>
and 1=1
</otherwise>
</choose>
</where>
</select>
<select id="findUsers" resultType="user">
select * from t_user
<where>
id in
<foreach collection="list" open="(" separator="," close=")" item="ids">
#{ids}
</foreach>
</where>
</select>
<update id="updateUser">
update t_user
<set>
<if test="name != null and name != ''">
name = #{name}
</if>
</set>
where id=#{id}
</update>
</mapper>
测试:
/**
*
* @Description: 一对一查询
* 第一方式:一次查询
* @author mao
* @date 2017年10月12日
*/
@Test
public void getCards(){
CardMapper mapper = session.getMapper(CardMapper.class);
List<Card> cards = mapper.getCards();
for (Card card : cards) {
System.out.println(card);
}
}
/**
*
* @Description: 一对一关系: n+1查询
* @author mao
* @date 2017年10月12日
*/
@Test
public void getCards2(){
CardMapper mapper = session.getMapper(CardMapper.class);
List<Card> cards2 = mapper.getCards2();
for (Card card : cards2) {
System.out.println(card);
}
}
一对多
数据库中一对多表关系,在mybatis的中的应用,数据库设计中,一个用户对应多本书。
用户表主键在书籍表中是外键,
书籍查询用户的信息:解决方案见:一对一
用户查询书籍的时候:
--n+1次查询sql
select * from t_user;
SELECT * FROM `t_book` where uesr_id = id;
--一次查询sql
select u.*,b.* from t_user u LEFT JOIN t_book b on u.ID = b.USER_ID;
UserMapper.xml
<mapper namespace="com.bjsxt.mapper.UserMapper">
<!-- user的resultMap -->
<resultMap type="user" id="getUser">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="pwd"/>
<result column="age" property="age"/>
</resultMap>
<resultMap type="user" id="getUsers" extends="getUser">
<!-- 构建一对多的关系
一个用户对应多个书籍
collection:用于处理一对多的关系的标签
property:对象中的管理对象的属性名称
javaType:使用集合类型
ofType:指的是集合的泛型对象类型
select:引用select语句,
如果该select在同一个映射文件中,直接使用select的id
如果该select不在同一个映射文件中,使用namespace.select的id
column:给select语句传递参数,select要的参数
select的参数命名,随便名称,但是如果该select还有其他方法调用,命名一定要规则
-->
<collection property="books" javaType="list" ofType="book"
select="com.bjsxt.mapper.BookMapper.getBooks"
column="id"
></collection>
</resultMap>
<!--
一般情况下:
n+1次查询:使用select 属性
一次查询:使用resultMap
-->
<resultMap type="user" id="getUsers1" extends="getUser">
<collection property="books" javaType="list" ofType="book"
resultMap="com.bjsxt.mapper.BookMapper.getBook"></collection>
</resultMap>
<select id="getUsers" resultMap="getUser">
SELECT * FROM t_user where id= #{id}
</select>
<!-- 一对多的: n+1次查询 -->
<select id="getUsers1" resultMap="getUsers">
select * from t_user
</select>
<!-- 一对多的:一次查询 -->
<select id="getUsers2" resultMap="getUsers1">
select u.*,b.*
from t_user u
LEFT JOIN
t_book b
on
u.ID=b.user_id
</select>
</mapper>
BookMapper.xml
<mapper namespace="com.bjsxt.mapper.BookMapper">
<resultMap type="book" id="getBook">
<id column="book_id" property="bookId"/>
<result column="book_name" property="bookName"/>
<result column="user_id" property="userId"/>
</resultMap>
<select id="getBooks" resultMap="getBook">
select * from t_book where user_id = #{id}
</select>
</mapper>
测试:
/**
*
* @Description: 一对多的 一次查询
* @author mao
* @date 2017年10月12日
*/
@Test
public void getUsers(){
UserMapper mapper = session.getMapper(UserMapper.class);
User userByIds = mapper.getUserByIds(2);
System.out.println(userByIds);
}
/**
*
* @Description: 一对多的 n+1此查询
* @author mao
* @date 2017年10月12日
*/
@Test
public void getUsers3(){
UserMapper mapper = session.getMapper(UserMapper.class);
User userById3 = mapper.getUserById3(2);
System.out.println(userById3);
}
多对多
数据库中多对多表关系,在mybatis的中的应用,一个学生对应多个课程,一个课程可以对应多个学生。一个学生表、一个课程表、一个中间表。
SELECT c.*,s.* FROM T_CLASS c,t_student s , t_student_class sc
where c.C_ID=sc.C_ID and s.S_ID = sc.S_ID
SELECT * from t_class
select * from t_student s ,t_student_class sc where s.S_ID = sc.S_ID and sc.C_ID=
StudentMapper.xml
<mapper namespace="com.bjsxt.mapper.StudentMapper">
<resultMap type="student" id="student">
<id column="s_id" property="id"/>
<result column="s_name" property="name"/>
<result column="s_sex" property="sex"/>
<result column="s_no" property="no"/>
</resultMap>
<resultMap type="student" id="students" extends="student">
<collection property="classesList" javaType="list" ofType="classes"
resultMap="com.bjsxt.mapper.ClassesMapper.classes">
</collection>
</resultMap>
<!-- 多对多 一次查询 -->
<select id="getStudents" resultMap="students">
SELECT c.*,s.*
FROM
T_CLASS c,
t_student s ,
t_student_class sc
where
c.C_ID=sc.C_ID
and
s.S_ID = sc.S_ID
</select>
<resultMap type="student" id="findstudent" extends="student">
<collection property="classesList" javaType="list" ofType="classes"
select="com.bjsxt.mapper.ClassesMapper.getClasses" column="s_id">
</collection>
</resultMap>
<!-- 多对多 n+1次查询-->
<select id="findStudents" resultMap="findstudent">
select * from t_student
</select>
</mapper>
ClassesMapper.xml
<mapper namespace="com.bjsxt.mapper.ClassesMapper">
<resultMap type="classes" id="classes">
<id column="c_id" property="id"/>
<result column="c_name" property="name"/>
<result column="c_no" property="no"/>
</resultMap>
<select id="getClasses" resultMap="classes">
select s.*
from
t_class s ,
t_student_class sc
where
s.c_id = sc.c_id
and sc.S_id = #{id}
</select>
</mapper>
测试类:
private SqlSession session;
@Before
public void getSession(){
session = MybatisUtil.getSession();
}
@After
public void closeSession(){
MybatisUtil.closeSession();
}
/**
*
* @Description: 多对多查询
* @author mao
* @date 2017年10月12日
*/
@Test
public void getStudent(){
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudents();
for (Student student : students) {
System.out.println(student);
}
}
/**
*
* @Description: 多对多查询 :n+1次查询
* @author mao
* @date 2017年10月12日
*/
@Test
public void findStudents(){
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> findStudents = mapper.findStudents();
for (Student student : findStudents) {
System.out.println(student);
}
}
}
Student.java
private Integer id;
private String name;
private String sex;
private String no;
private List<Classes> classesList;
//自行生成对应getter/setter方法
1.5自关联
在数据表的一张表中,构建层级关系,一般有一个字段作为定义层级,最高级只有一个。
配置文件:
<?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.bjsxt.mapper.CityMapper">
<resultMap type="city" id="city">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="parent_id" property="parentId"/>
</resultMap>
<resultMap type="city" id="getCity" extends="city">
<collection property="citys" javaType="list" ofType="city"
select="getCitys1"
column="id"
></collection>
</resultMap>
<!-- 找到根数据 -->
<select id="getCitys" resultMap="getCity">
select * from t_city where parent_id = 0
</select>
<!-- 找到他的一级子节点 -->
<select id="getCitys1" resultMap="city">
select * from t_city where parent_id=#{id}
</select>
<!-- 使用代码,解决自关联 -->
<select id="getCitys2" resultMap="city">
select * from t_city
</select>
</mapper>
实现类:
/**
*
* @ClassName:TestCity
* @Description:测试 自连接
* @Company: 北京尚学堂科技有限公司 www.bjsxt.com
* @author mao
* @date 2017年10月31日
*/
public class TestCity {
private SqlSession session;
@Before
public void getSession(){
session = MybatisUtil.getSession();
}
@After
public void closeSession(){
MybatisUtil.closeSession();
}
/**
* 代码实现自关联
* 1.查询所有的数据
* 2.在代码中使用循环来创建关联关系
*/
@Test
public void getCitys1(){
CityMapper mapper = session.getMapper(CityMapper.class);
List<City> citys2 = mapper.getCitys2();
City root = null;
for (City city : citys2) {
//当数据的父主键为0的时候,说明该city为根节点
if(city.getParentId().equals(0)){
root = city;
}
for (City city1 : citys2) {
if(city.getId().equals(city1.getParentId())){
city.getCitys().add(city1);
}
}
}
System.out.println(root);
}
/**
*
* @Description:自关联
* 使用一对多的关系来处理自关联
* 如果层级多的话,很难实现
* @author mao
* @date 2017年10月31日
*/
@Test
public void getCitys(){
CityMapper mapper = session.getMapper(CityMapper.class);
City citys = mapper.getCitys();
System.out.println(citys);
}
}
注解开发
注解开发是web3.0之后提出的标准,它主要目的就在代码不使用配置文件(xml)或者尽可能的不使用配置文件。
Mybatis的注解开发,在实际项目中,不怎么经常使用,因为在配置文件中写sql语句,比使用注解写sql要简单、明了。Mybatis的注解开发处理复杂逻辑,很费劲。
注解一般写在方法、类、变量的上面进行标识
public interface UserMapper {
/**
* 查询所有用户信息
* 1.简单类型的参数传递
* 2.对象类型
* 3.map类型
*/
@Select(value="select * from t_user where id= #{id}")
List<User> getUsers(Integer id);
/**
* 新增
* 如果注解中只有一个value属性的话,value可以省略
* @SelectKey:
* resultType:返回值类型Class<?> ,java.lang.Integer.class
* before:返回值是 boolean,如果是值true,表示是在执行sql语句之前执行,
* 如果值false:表在sql执行之后执行
* keyColumn:对应数据库的表主键
* keyProperty:对应的是对象的主键
* statement:要执行的sql语句
*/
@Insert("insert into t_user(name,pwd,age) values(#{name},#{pwd},#{age})")
@SelectKey(resultType=java.lang.Integer.class,before=false,
keyColumn="id",keyProperty="id",statement="select @@identity as id")
int saveUser(User user);
/**
* 修改
*/
@Update("update t_user set name=#{name} , age=#{age} where id=#{id}")
int updateUser(User user);
/**
* 删除
*/
@Delete("delete from t_user where id=#{id}")
int deleteUser(Integer id);
}
测试类:
/**
*
* @Description: 注解开发,查询
* @author mao
* @date 2017年10月13日
*/
@Test
public void getUsers(){
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.getUsers(2);
for (User user : users) {
System.out.println(user);
}
}
/**
*
* @Description: 注解开发 新增
* @author mao
* @date 2017年10月13日
*/
@Test
public void saveUser(){
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User("张000", "zhang000", 44);
int saveUser = mapper.saveUser(user);
session.commit();
System.out.println(saveUser);
System.out.println(user);
}
/**
*
* @Description: 注解开发 修改数据
* @author mao
* @date 2017年10月13日
*/
@Test
public void updateUser(){
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User();
user.setName("赵6666");
user.setAge(55);
user.setId(32);
int updateUser = mapper.updateUser(user);
session.commit();
System.out.println(updateUser);
}
/**
*
* @Description: 注解开发 删除
* @author mao
* @date 2017年10月13日
*/
@Test
public void deleteUser(){
UserMapper mapper = session.getMapper(UserMapper.class);
int deleteUser = mapper.deleteUser(32);
session.commit();
System.out.println(deleteUser);
}
Mybatis.cfg.xml,中mapper文件的引用还是包引用
<mappers>
<!-- <mapper resource="com/bjsxt/mapper/user.mapper.xml"/> -->
<package name="com.bjsxt.mapper"/>
</mappers>
运行原理
MyBatis内部原理机制参考博客:
http://blog.csdn.net/column/details/mybatis-principle.html