1.什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 实体类 映射成数据库中的记录
- Mybatis官方文档 : http://www.mybatis.org/mybatis-3/zh/index.html
- GitHub : https://github.com/mybatis/mybatis-3
- MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射
第一个Mybatis程序
思路:搭建环境–>导入Mybatis–>编写代码–>测试
1.搭建环境 和 编写实体类
CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`name`,`pwd`) values (1,'狂神','123456'),(2,'张三','abcdef'),(3,'李四','987654');
package com.jsp.pojo;
public class User {
private Integer id;
private String name;
private String pwd;
public User() {
}
public User(Integer id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getname() {
return name;
}
public void setUsername(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
2.导入Mybatis相关依赖
<dependency>
//mybatis依赖
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
//数据库连接依赖
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
//资源过滤
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
3.编写Mybatis配置文件
<?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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="1233"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/jsp/dao/UserMapper.xml"/>
</mappers>
</configuration>
4.编写Mybatis工具类
package com.jsp.utils;
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 java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "Mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
5.编写Mapper接口
package com.jsp.dao;
import com.jsp.pojo.User;
import java.util.List;
public interface UserMapper {
//查询所有用户
List<User> selectUser();
}
6.编写Mapper.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.jsp.dao.UserMapper">
<select id="selectUser" resultType="com.jsp.pojo.User">
select * from user;
</select>
</mapper>
7.Junit测试
package com.jsp.dao;
import com.jsp.pojo.User;
import com.jsp.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MyTest {
@Test
public void selectUser() {
SqlSession sqlSession = MybatisUtils.getSession();
// 方式一
// UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// List<User> users = mapper.selectUser();
// 方式二
List<User> users = sqlSession.selectList("com.jsp.dao.UserMapper.selectUser");
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
}
CRUD操作
- 配置文件中namespace中的名称必须对应Mapper接口或者Dao接口的完整包名,必须一致!!!
<select id="selectUserByIdAndPassword" parameterType="map" resultType="user"> select * from user where name = #{name} and pwd = #{pwd} </select>
- id : 接口中的方法名与映射文件中的sql语句id必须一致
- parameterType : 参数类型
- resultType : 结果集类型
- 传入SQL语句的参数类型 。【万能的Map,可以多尝试使用】
- Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型
//通过密码和名字查询用户
User selectUserByNP(@Param("username") String username,@Param("pwd") String pwd);
/*
<select id="selectUserByNP" resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
*/
万能的map
1.接口
User selectUserByNP2(Map<String,Object> map);
2.sql语句
<select id="selectUserByNP2" parameterType="map" resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
3.调用方法
Map<String, Object> map = new HashMap<String, Object>();
map.put("username","小明");
map.put("pwd","123456");
User user = mapper.selectUserByNP2(map);
设置别名
<!--配置别名,注意顺序 当这样配置时,User可以用在任何使用com.jsp.pojo.User的地方-->
<typeAliases>
<typeAlias type="com.jsp.pojo.User" alias="User"/>
</typeAliases>
ResultMap
- 解决查询为null的问题 (属性名和字段名不一致)
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
注解开发
- 使用注解开发就不需要Mapper.xml映射文件了
1.在接口中添加注解
//查询全部用户
@Select("select id,name,pwd password from user")
public List<User> getAllUser();
2.在Mybatis-config.xml中绑定接口
<!--使用class绑定接口-->
<mappers>
<mapper class="com.kuang.mapper.UserMapper"/>
</mappers>
3.测试
@Test
public void testGetAllUser() {
SqlSession session = MybatisUtils.getSession();
//本质上利用了jvm的动态代理机制
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.getAllUser();
for (User user : users){
System.out.println(user);
}
session.close();
}
- 关于@Param
@Param注解用于给方法参数起一个名字。以下是总结的使用原则:
1.在方法只接受一个参数的情况下,可以不使用@Param。
2.在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
3.如果参数是 JavaBean , 则不能使用@Param。
4.不使用@Param注解时,参数只能有一个,并且是Javabean
一对多和多对一
多对一
1.数据库设计
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');
2.引入Lombok插件
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
3.编写实体类
@Data //GET,SET,ToString,有参,无参构造
public class Teacher {
private int id;
private String name;
}
@Data
public class Student {
private int id;
private String name;
//多个学生可以是同一个老师,即多对一
private Teacher teacher;
}
4.编写Mapper接口
public interface StudentMapper {
}
public interface TeacherMapper {
}
5.编写Mapper.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.kuang.mapper.StudentMapper">
</mapper>
<?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.kuang.mapper.TeacherMapper">
</mapper>
- 按照结果进行嵌套处理就像SQL中的联表查询(推荐)
多对一 : association
<!--
按查询结果嵌套处理
思路:
1. 直接查询出结果,进行结果集的映射
-->
<select id="getStudents2" resultMap="StudentTeacher2" >
select s.id sid, s.name sname , t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<!--关联对象property 关联对象在Student实体类中的属性-->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
一对多 : collection
<mapper namespace="com.kuang.mapper.TeacherMapper">
<!--
思路:
1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
2. 对查询出来的操作做结果集映射
1. 集合的话,使用collection!
JavaType和ofType都是用来指定对象类型的
JavaType是用来指定pojo中属性的类型
ofType指定的是映射到list集合属性中pojo的类型。
-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname , t.name tname, t.id tid
from student s,teacher t
where s.tid = t.id and t.id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
</mapper>
- 小结:
JavaType和ofType都是用来指定对象类型的
JavaType是用来指定pojo中属性的类型
ofType指定的是映射到list集合属性中pojo的类型
一对多 ( 一个老师对应多个学生 )
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Student implements Serializable {
private static final long serialVersionUID=1L;
/**
* 学生id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 学生姓名
*/
private String sName;
/**
* 老师id
*/
private Integer tId;
// private Teacher teacher;
}
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Teacher implements Serializable {
private static final long serialVersionUID=1L;
/**
* 老师id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 老师姓名
*/
private String tName;
// 一个老师对应多个学生
private List<Student> students;
}
- mapper
public interface TeacherMapper extends BaseMapper<Teacher> {
List<Teacher> getTeacher();
}
- 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.jsp.mapper.TeacherMapper">
<!-- 一对多 -->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.s_name sname, t.t_name tname, t.id tid
from student s, teacher t
where s.t_id = t.id
</select>
<!-- property: pojo实体类中的属性,column: 数据库中的字段或者sql语句中的别名 -->
<resultMap id="TeacherStudent" type="com.jsp.entity.Teacher">
<id property="id" column="tid"/>
<result property="tName" column="tname"/>
<collection property="students" ofType="com.jsp.entity.Student">
<result property="id" column="sid"/>
<result property="sName" column="sname"/>
<result property="tId" column="tid" />
</collection>
</resultMap>
</mapper>
- 结果
多对一 ( 多个学生对应一个老师 )
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Student implements Serializable {
private static final long serialVersionUID=1L;
/**
* 学生id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 学生姓名
*/
private String sName;
/**
* 老师id
*/
private Integer tId;
// 多个学生对应一个老师
private Teacher teacher;
}
- mapper
public interface StudentMapper extends BaseMapper<Student> {
List<Student> getStudents();
}
- 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.jsp.mapper.StudentMapper">
<!-- 多对一 -->
<select id="getStudents" resultMap="StudentTeacher">
select s.id sid, s.s_name sname, s.t_id, t.id tid, t.t_name tname
from student s, teacher t
where s.t_id = t.id
</select>
<resultMap id="StudentTeacher" type="com.jsp.entity.Student">
<id property="id" column="sid"/>
<result property="sName" column="sname"/>
<result property="tId" column="t_id"/>
<!--关联对象property 关联对象在Student实体类中的属性-->
<association property="teacher" javaType="com.jsp.entity.Teacher">
<id property="id" column="tid"/>
<result property="tName" column="tname"/>
</association>
</resultMap>
</mapper>
- 结果
- 如果是多对一的话,实体类中就写对象属性,如果是一对多的话,实体类中就写集合类型的属性
自定义结果集(DTO) Data Transfer Object
- 多对一
-
首先将常用的数据库字段定义为一个DTO实体类
-
编写mapper
-
编写xml文件
-
测试
- 一对多
SELECT t.id tid , t.t_name tname, s.id sid, s.s_name sname
FROM teacher t
INNER JOIN student s
ON t.id = s.t_id
动态sql
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
实例 :
- if :
<!--需求1:
根据作者名字和博客名字来查询博客!
如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
select * from blog where title = #{title} and author = #{author}
-->
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog where
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
- where
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
- Set
<select id="updateStudent" resultType="java.lang.Integer" parameterType="com.jsp.entity.Student">
UPDATE student s
<set>
<if test="sName != null and sName != ''">
s.s_name = #{sName},
</if>
<if test="tId != null and tId != ''">
s.t_id = #{tId}
</if>
</set>
WHERE s.id = #{id}
</select>
<!-- update
这里使用trim标签来解决update语句中逗号处理问题
prefix:前缀
prefixoverride:去掉第一个and或者是or
suffix:后缀
suffixOverrides:去掉最后一个and或者是or,或者去掉最后一个逗号
-->
<select id="updateStudent" resultType="java.lang.Integer" parameterType="com.jsp.entity.Student">
UPDATE student s
<trim prefix="set" suffixOverrides=",">
<if test="sName != null and sName != ''">
s.s_name = #{sName},
</if>
<if test="tId != null and tId != ''">
s.t_id = #{tId}
</if>
</trim>
WHERE s.id = #{id}
</select>
<!--注意set是用的逗号隔开-->
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id};
</update>
- choose
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
- Foreach
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from blog where 1=1 and (id=1 or id=2 or id=3)
-->
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
Mybatis缓存
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
- Mybatis定义了缓存接口Cache
一级缓存
-
与数据库同一次会话期间查询到的数据会放在本地缓存中。
-
以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库