一.MyBatis持久层框架
1. 概念
MyBatis的前身就是iBatis,iBatis本是apache的一个开源项目,2010年5月这个项目由apahce sofeware foundation 迁移到了google code,并且改名为MyBatis。
MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。
特点:
1.简化JDBC的开发
2.能够更好的完成ORM(对象关系映射)
2.内部组件结构图
1.核心配置文件
mybatis-config.xml配置了事务管理,数据源
2.映射文件
XxxMapper.xml 存放大量的CRUD的SQL语句
3.核心工具类
会话工厂SqlSessionFactory : 产生会话
会话SqlSession : 执行SQL语句
4.ORM
是指对象关系映射.
把表里的字段的值 查到 自动交给 类里的属性 保存
3.入门案例
准备库,表,数据
修改pom.xml,添加mybatis的jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cgb2106boot01</artifactId>
<groupId>cn.tedu</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>day17</artifactId>
<dependencies>
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!--jdbc依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
创建核心配置文件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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!--enviroments可以配置多个数据库的信息,default指定默认的环境-->
<environments default="test">
<environment id="test">
<!--使用的事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置了数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
创建映射文件UserMapper.xml,写SQL
<?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">
<!-- mybatis的核心配置文件 -->
<!--这个文件是映射文件,写SQL的
namespace用来作为一个mapper.xnl文件的唯一标识
-->
<mapper namespace="userMapper">
<!--查id=1的用户信息
id是这条SQL的唯一标识
resultType的值用来封装查到的结果-ORM
-->
<select id = "getById" resultType="cn.tedu.pojo.User">
select * from user where id = 1;
</select>
</mapper>
封装pojo类
package cn.tedu.pojo;
//属性的名字 必须 和表里的字段名 一致
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {
private Integer id;
private String name;
private String addr;
private Integer age;
}
二.Mybatis入门案例
1.导入mybatis的jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cgb2106boot03</artifactId>
<groupId>cn.tedu</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>day17</artifactId>
<dependencies>
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!--jdbc依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
</dependencies>
</project>
2.核心配置文件
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
<environments default="test">
<environment id="test">
<!--使用的事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置了数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
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">
<!--这个文件是映射文件,写SQL的
namespace用来作为一个mapper.xml文件的唯一标识
-->
<mapper namespace="userMapper">
<!-- 查id=1的用户信息
id是这条SQL的唯一标识
resultType的值用来封装查到的结果,ORM
-->
<select id="getById" resultType="cn.tedu.pojo.User">
select * from user where id=1
</select>
</mapper>
4.创建User类
package cn.tedu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
//注意:::属性的名 和 表里的字段名 必须一致,否则无法ORM
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class User {
private Integer id;
private String name;
private String addr;
private Integer age;
}
5.测试类
package cn.tedu.test;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
public class Test1 {
@Test
public void get() throws IOException {
InputStream in = Resources.getResourceAsStream(
"mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(in);
SqlSession session = factory.openSession();
Object o = session.selectOne("userMapper.getById");
//User(id=1, name=hanmeimei, addr=北京, age=28)
System.out.println(o);
}
}
6.总结
三.Mybatis的练习
1.修改映射文件UserMapper.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">
<!--这个文件是映射文件,写SQL的
namespace用来作为一个mapper.xml文件的唯一标识
-->
<mapper namespace="userMapper">
<!--
面试题:SQL动态获取参数时,可以用#或者$
$ 底层用了低级传输器,可能发生SQL注入攻击,低效,不拼串,可能发生SQL语法错误
# 底层用了高级传输器,安全,高效,会自动拼接字符串 'xiongda'
-->
<!-- 查id=1的用户信息
id是这条SQL的唯一标识
resultType的值用来封装查到的结果,ORM
-->
<select id="getById" resultType="cn.tedu.pojo.User">
select * from user where id=${id}
</select>
<!-- 查询所有user -->
<select id="getAll" resultType="cn.tedu.pojo.User">
select * from user
</select>
<!-- 查询hanmeimei的,固定语法#{??}用来解析SQL的参数-->
<select id="getByName" resultType="cn.tedu.pojo.User">
select * from user where name=#{name}
</select>
</mapper>
2.修改测试类
package cn.tedu.test;
import cn.tedu.pojo.User;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test1 {
@Test
public void get() throws IOException {
//读取配置文件
InputStream in = Resources.getResourceAsStream(
"mybatis-config.xml");
//创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(in);
//开启会话,准备执行SQL
SqlSession session = factory.openSession();
//定位SQL(namespace的值.id的值),并执行
//selectOne执行查询的SQL,并只会返回一个结果
Object o = session.selectOne("userMapper.getById",2);
//User(id=1, name=hanmeimei, addr=北京, age=28)
System.out.println(o);
//定位SQL(namespace的值.id的值),并执行
//selectList执行查询的SQL,并返回多个结果
List<User> list = session.selectList("userMapper.getAll");
for(User u : list){
System.out.println(u);
}
//定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
User u = session.selectOne(
"userMapper.getByName","xiongda");
System.out.println(u);
}
}
3.总结
参数值:paramterType
指定参数类型,通常制定一个对象类型。
返回值:resultType
非常重要的东西,即完成ORM的映射关系所在。这里指定的cd.tedu.mybatis.domain.User代表把结果集转换成一个User对象实例。
返回值:resultMap
resultMap 用于对复杂对象结构时,对应的ResultMap结构名称
#和$的区别(面试题)
两种方式都可以获取参数的值。区别如下:
(推荐!)#: 使用#{parameterName}引用参数的时候,Mybatis会把这个参数认为是一个字符串,例如传入参数是"Smith",那么在SQL(Select * from emp where name = #{employeeName})使用的时候就会转换为Select * from emp where name = ‘Smith’。
$: 不做字符串拼接,SQL(Select * from emp where name = ${employeeName})使用的时候就会转换为Select * from emp where name = Smith。此时,如果字段是varchar类型直接抛出SQL异常。
从安全性上考虑,能使用#尽量使用#来传参,因为这样可以有效防止SQL注入的问题。
SQL中有特殊字符
当SQL中有特殊字符,mybatis不能正常解析时,
用<![CDATA[ ?? ]]>括起来就解决了 <![CDATA[ and age<=#{age} ]]>
<![CDATA[
and age<=#{age}
]]>
where age<10写成 where age <;10
四.优化配置
1.别名:alias
在sqlMapConfig.xml配置,在映射文件中直接写对象名称即可
<typeAliases>
<typeAlias type="cn.mybatis.pojo.User" alias="User"/>
</typeAliases>
修改核心配置文件,加别名的代码
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!--配置别名,给指定类起一个指定的别名-->
<typeAliases>
<typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
</typeAliases>
<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
<environments default="test">
<environment id="test">
<!--使用的事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置了数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&serverTimezone=Asia/Shanghai" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="UserMapper.xml"></mapper>
</mappers>
</configuration>
修改映射文件,使用别名
<?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">
<!--这个文件是映射文件,写SQL的
namespace用来作为一个mapper.xml文件的唯一标识
-->
<mapper namespace="userMapper">
<!--
面试题:SQL动态获取参数时,可以用#或者$
$ 底层用了低级传输器,可能发生SQL注入攻击,低效,不拼串,可能发生SQL语法错误
# 底层用了高级传输器,安全,高效,会自动拼接字符串 'xiongda'
-->
<!-- 查id=1的用户信息
id是这条SQL的唯一标识
resultType的值用来封装查到的结果,ORM
-->
<select id="getById" resultType="User">
select * from user where id=${id}
</select>
<!-- 查询所有user -->
<select id="getAll" resultType="User">
select * from user
</select>
<!-- 查询hanmeimei的,固定语法#{??}用来解析SQL的参数-->
<select id="getByName" resultType="User">
select * from user where name=#{name}
</select>
</mapper>
五.接口开发
1.概述
为了优化定位SQL的字符串拼接过程,namespace的值,id的值
步骤:
0.创建接口 创建方法
1.namespace的值是接口的全路径
2.id的值,是接口里的方法名
2.使用
需求:查询id=1的部门信息
创建Dept类
package cn.tedu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
//完成ORM,属性名 必须和字段名 一致
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Dept {
private Integer id;
private String dname;
private String loc;
}
创建DeptMapper.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="deptMapper">
<select id="getById" resultType="Dept">
select * from dept where id=1
</select>
</mapper>
修改核心配置文件,加了别名和引入Mapper
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!--配置别名,给指定类起一个指定的别名-->
<typeAliases>
<typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
<typeAlias type="cn.tedu.pojo.Dept" alias="Dept"></typeAlias>
</typeAliases>
<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
<environments default="test">
<environment id="test">
<!--使用的事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置了数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&serverTimezone=Asia/Shanghai" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="UserMapper.xml"></mapper>
<mapper resource="DeptMapper.xml"></mapper>
</mappers>
</configuration>
测试
package cn.tedu.test;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test1 {
@Test
public void get() throws IOException {
//读取配置文件
InputStream in = Resources.getResourceAsStream(
"mybatis-config.xml");
//创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(in);
//开启会话,准备执行SQL
SqlSession session = factory.openSession();
//定位SQL(namespace的值.id的值),并执行
//selectOne执行查询的SQL,并只会返回一个结果
Object o = session.selectOne("userMapper.getById",2);
//User(id=1, name=hanmeimei, addr=北京, age=28)
System.out.println(o);
//定位SQL(namespace的值.id的值),并执行
//selectList执行查询的SQL,并返回多个结果
List<User> list = session.selectList("userMapper.getAll");
for(User u : list){
System.out.println(u);
}
//定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
User u = session.selectOne(
"userMapper.getByName","xiongda");
System.out.println(u);
//定位SQL(namespace的值.id的值)
Dept d = session.selectOne("deptMapper.getById");
System.out.println(d);
}
}
3.改造
创建接口
package cn.tedu.dao;
import cn.tedu.pojo.Dept;
//接口的全路径=映射文件中namespace的值
//接口的方法名=映射文件中id的值
public interface DeptMapper {
Dept getById();
}
改造映射文件
<?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.tedu.dao.DeptMapper">
<!--id=接口里的方法名-->
<select id="getById" resultType="Dept">
select * from dept where id=1
</select>
</mapper>
改造测试类
package cn.tedu.test;
import cn.tedu.dao.DeptMapper;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test1 {
@Test
public void get() throws IOException {
//读取配置文件
InputStream in = Resources.getResourceAsStream(
"mybatis-config.xml");
//创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(in);
//开启会话,准备执行SQL
SqlSession session = factory.openSession();
//定位SQL(namespace的值.id的值),并执行
//selectOne执行查询的SQL,并只会返回一个结果
Object o = session.selectOne("userMapper.getById",2);
//User(id=1, name=hanmeimei, addr=北京, age=28)
System.out.println(o);
//定位SQL(namespace的值.id的值),并执行
//selectList执行查询的SQL,并返回多个结果
List<User> list = session.selectList("userMapper.getAll");
for(User u : list){
System.out.println(u);
}
//定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
User u = session.selectOne(
"userMapper.getByName","xiongda");
System.out.println(u);
//定位SQL(namespace的值.id的值)
// Dept d = session.selectOne("deptMapper.getById");
// System.out.println(d);
//获取了指定的接口
DeptMapper mapper = session.getMapper(DeptMapper.class);
//调用接口里的方法
Dept dd = mapper.getById();
System.out.println(dd);
}
}
总结
六.练习接口开发
1.修改 接口文件
package cn.tedu.dao;
import cn.tedu.pojo.Dept;
import java.util.List;
//接口的全路径=映射文件中namespace的值
//接口的方法名=映射文件中id的值
public interface DeptMapper {
Dept getById(); //根据id查
List<Dept> getByName(String dname);//根据名字查
void save(Dept dept);//新增部门记录
}
2.修改映射文件
<?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.tedu.dao.DeptMapper">
<!--新增部门记录-->
<insert id="save">
insert into dept values(#{id},#{dname},#{loc})
</insert>
<select id="getByName" resultType="Dept">
select * from dept where dname=#{dname};
</select>
<!--id=接口里的方法名-->
<select id="getById" resultType="Dept">
select * from dept where id=1
</select>
</mapper>
3.修改 测试 文件
package cn.tedu.test;
import cn.tedu.dao.DeptMapper;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test1 {
@Test
public void get() throws IOException {
//读取配置文件
InputStream in = Resources.getResourceAsStream(
"mybatis-config.xml");
//创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(in);
//开启会话,准备执行SQL
SqlSession session = factory.openSession();
//定位SQL(namespace的值.id的值),并执行
//selectOne执行查询的SQL,并只会返回一个结果
Object o = session.selectOne("userMapper.getById",2);
//User(id=1, name=hanmeimei, addr=北京, age=28)
System.out.println(o);
//定位SQL(namespace的值.id的值),并执行
//selectList执行查询的SQL,并返回多个结果
List<User> list = session.selectList("userMapper.getAll");
for(User u : list){
System.out.println(u);
}
//定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
User u = session.selectOne(
"userMapper.getByName","xiongda");
System.out.println(u);
//定位SQL(namespace的值.id的值)
// Dept d = session.selectOne("deptMapper.getById");
// System.out.println(d);
//获取了指定的接口
DeptMapper mapper = session.getMapper(DeptMapper.class);
//调用接口里的方法
Dept dd = mapper.getById();
System.out.println(dd);
List<Dept> ds = mapper.getByName("java教研部");
for (Dept d : ds) {
System.out.println(d);
}
Dept dept = new Dept();
dept.setId(100).setDname("ios开发部").setLoc("上海");
mapper.save(dept);
//mybatis不会自动提交事务,增删改需要自己提交事务
session.commit();
}
}
七.动态SQL
1.概述
利用mybatis框架提供一些标签,完成SQL的拼接
利用标签
sql:提取SQL片段,提高SQL的复用.
include:引入指定的SQL片段
<sql id="cols">
id,title,sell_point,price,num,barcode,image,cid,status,created,updated
</sql>
<select id="find" resultType="Item" parameterType="Item">
SELECT <include refid="cols"/> FROM tb_item
</select>
if:用来判断,满足条件才拼接SQL
<select id="find" resultType="Item" parameterType="Item">
SELECT <include refid="cols"/> FROM tb_item where
<if test="title != null"> title like #{title} </if>
<if test="sellPoint != null">and sell_point like #{sellPoint}</if>
</select>
2.修改映射文件,实现动态SQL
<?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.tedu.dao.DeptMapper">
<!-- 提取SQL片段,提高SQL片段复用性 -->
<sql id="cols">
id,dname,loc
</sql>
<!-- 引用SQL片段 -->
<select id="getByName" resultType="Dept">
select
<include refid="cols"></include>
from dept
<if test="dname != null">
where dname=#{dname}
</if>
</select>
<!--id=接口里的方法名-->
<select id="getById" resultType="Dept">
select
<include refid="cols"></include>
from dept where id=1
</select>
<!--新增部门记录-->
<insert id="save">
insert into dept values(#{id},#{dname},#{loc})
</insert>
</mapper>
3.foreach标签
修改映射文件
<?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.tedu.dao.DeptMapper">
<!-- 提取SQL片段,提高SQL片段复用性 -->
<sql id="cols">
id,dname,loc
</sql>
<!-- delete from dept where id in(1,2,3)-->
<delete id="delete">
delete from dept where id in(
/*foreach用来完成遍历
collection表示要遍历哪种集合里的数据,值是固定值:array/list/Map.key
item表示即将遍历到的数据,separator是分隔符,#{ids}获取遍历到的数据
*/
<foreach collection="array" item="ids" separator=",">
#{ids}
</foreach>
)
</delete>
<!-- 引用SQL片段 -->
<select id="getByName" resultType="Dept">
select
<include refid="cols"></include>
from dept
<if test="dname != null">
where dname=#{dname}
</if>
</select>
<!--id=接口里的方法名-->
<select id="getById" resultType="Dept">
select
<include refid="cols"></include>
from dept where id=1
</select>
<!--新增部门记录-->
<insert id="save">
insert into dept values(#{id},#{dname},#{loc})
</insert>
</mapper>
修改接口文件
package cn.tedu.dao;
import cn.tedu.pojo.Dept;
import java.util.List;
//接口的全路径=映射文件中namespace的值
//接口的方法名=映射文件中id的值
public interface DeptMapper {
Dept getById(); //根据id查
List<Dept> getByName(String dname);//根据名字查
void save(Dept dept);//新增部门记录
void delete(int[] a);//删除
}
修改测试类
package cn.tedu.test;
import cn.tedu.dao.DeptMapper;
import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test1 {
@Test
public void get() throws IOException {
//读取配置文件
InputStream in = Resources.getResourceAsStream(
"mybatis-config.xml");
//创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(in);
//开启会话,准备执行SQL
SqlSession session = factory.openSession();
//定位SQL(namespace的值.id的值),并执行
//selectOne执行查询的SQL,并只会返回一个结果
Object o = session.selectOne("userMapper.getById",2);
//User(id=1, name=hanmeimei, addr=北京, age=28)
System.out.println(o);
//定位SQL(namespace的值.id的值),并执行
//selectList执行查询的SQL,并返回多个结果
List<User> list = session.selectList("userMapper.getAll");
for(User u : list){
System.out.println(u);
}
//定位SQL(namespace的值.id的值),并执行,并给SQL传入参数
User u = session.selectOne(
"userMapper.getByName","xiongda");
System.out.println(u);
//定位SQL(namespace的值.id的值)
// Dept d = session.selectOne("deptMapper.getById");
// System.out.println(d);
//获取了指定的接口
DeptMapper mapper = session.getMapper(DeptMapper.class);
//调用接口里的方法
Dept dd = mapper.getById();
System.out.println(dd);
List<Dept> ds = mapper.getByName(null);
for (Dept d : ds) {
System.out.println(d+"=================");
}
Dept dept = new Dept();
dept.setId(null).setDname("ios开发部").setLoc("上海");
mapper.save(dept);
//mybatis不会自动提交事务,增删改需要自己提交事务
session.commit();
mapper.delete(new int[]{103,104});
session.commit();
}
}
总结
八.ResultMap
1.概述
resultType只能完成简单的ORM,只能完成那些 字段名 和 属性名一致的情况
字段名 和 属性名 不一样的情况,resultType必须换成resultMap,否则无法ORM
2.测试
项目结构
创建了表,加了记录
CREATE TABLE `user_info` (
`id` int(11) NOT NULL auto_increment,
`user_name` varchar(20) default NULL,
`user_addr` varchar(20) default NULL,
`user_age` int(11) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
修改pom.xml,添加mybatis的jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cgb2106boot03</artifactId>
<groupId>cn.tedu</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>day19</artifactId>
<dependencies>
<!--mybatis依赖包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!--jdbc依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
</dependencies>
</project>
创建核心配置文件
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
<environments default="test">
<environment id="test">
<!--使用的事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置了数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&serverTimezone=Asia/Shanghai" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="userInfoMapper.xml"></mapper>
</mappers>
</configuration>
创建映射文件
<?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.tedu.dao.UserInfoMapper">
<!-- 查询所有 ,字段名和属性名不一样,resultType换成resultMap
resultType="cn.tedu.pojo.UserInfo"
-->
<!-- ORM:是指把字段的值查到以后 交给 同名属性保存
使用resultMap: 字段名 和 属性名 不一样
id是唯一标识 type是类的全路径
-->
<resultMap id="abc" type="cn.tedu.pojo.UserInfo">
<result column="user_name" property="userName"></result>
<result column="user_addr" property="userAddr"></result>
<result column="user_age" property="userAge"></result>
</resultMap>
<!--resultMap属性是解决了resultType解决不了的问题,引用指定的resultMap-->
<select id="selectList" resultMap="abc">
select * from user_info
</select>
</mapper>
创建接口类
package cn.tedu.dao;
import cn.tedu.pojo.UserInfo;
import java.util.List;
public interface UserInfoMapper {
List<UserInfo> selectList();//查询所有
}
创建pojo类
package cn.tedu.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class UserInfo {
private Integer id;
private String userName;
private String userAddr;
private Integer userAge;
}
测试
package cn.tedu.test;
import cn.tedu.dao.UserInfoMapper;
import cn.tedu.pojo.UserInfo;
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 org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class Test1 {
@Test
public void all() throws IOException {
InputStream in = Resources.getResourceAsStream(
"mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder()
.build(in);
//true表示自动提交事务
SqlSession session = factory.openSession(true);
//获取指定接口
UserInfoMapper mapper = session.getMapper(UserInfoMapper.class);
//调用方法
List<UserInfo> list = mapper.selectList();
for (UserInfo uf : list) {
//UserInfo(id=1, userName=null, userAddr=null, userAge=null)
System.out.println(uf);
}
}
}
总结
3.优化简化resultmap
第一步:在核心配置文件中开启驼峰规则:
<?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">
<!-- mybatis的核心配置文件,配置了事务管理,数据源 -->
<configuration>
<settings>
<!--开启驼峰规则,简化resultMap的编写-->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<!--environments可以配置多个数据库的连接信息,default指定默认的环境-->
<environments default="test">
<environment id="test">
<!--使用的事务管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置了数据源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisdb2?characterEncoding=utf8&serverTimezone=Asia/Shanghai" />
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="userInfoMapper.xml"></mapper>
</mappers>
</configuration>
第二步:resultMap标签中添加新属性 autoMapping=“true”
扩展
JDBC和MyBatis的区别?
JDBC是java提供了一套专门用于和数据库对接的api,java.sql.*,其规范了如何和数据库进行对接,实现由各数据库厂商进行各自的实现和扩展。学习JDBC重点在学习如何使用其api。
MyBatis框架是轻量级封装了JDBC,我们已经看不到这些api,连接connection、语句preparedstatement、结果集ResultSet,而关注的是mybatis框架体系如何去使用,一旦写好,我们关注的是java对象。
XML和接口方式的区别?
MyBatis提供了两种操作数据库的方式,一种是通过xml映射文件,一种是通过java的接口类。按面向对象方式更加推荐接口方式,但如果复杂的多表映射,仍然需要使用xml映射文件的ResultMap方式实现。
接口只是假象,其底层仍然是通过xml实现,好不容易实现了一套方式,怎忍丢掉呢?可以做个测试就知道它底层怎么实现的?把xml中的sql删除,它就玩不转了。
接口方式怎么找到xml执行的?
SqlSession的getMapper方法找到类,通过反射可以获取到类的全路径(包名.类名),相加后就定位到某个xml的命名空间namespace,在根据调用的方法去找到xml中某个标签的id属性。从而实现价值接口,调用接口的方法而间接找到xml中的标签,通过解析xml获取这个标签的内容,从而获取到sql语句。