介绍
MyBatis是一个支持普通SQL查询、存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Pain Old java Objects,普通的Java对象) 映射成数据库中的记录。
mybatis的功能架构分为三层:
API接口层
数据处理层
基础支撑层
mybatis特点:属于持久层ORM框架
1.持久层:讲内存中对象数据,转移到数据库中的过程持久层
2.ORM Object Relational Mapping 对象关系映射框架
类 表
属性 字段
对象 记录
3.半自化 自动化
mybatis 半自动化
表需要手动进行设计
提供sql
依赖与数据库平台
优点:学习使用简单,优化灵活,适合做互联网项目
hibernate 自动化ORM框架
表可以通过框架自动创建
省略一些基本的sql
不依赖与数据库平台
缺点:学生成本高,优化难度大,适合于传统框架,不适合做大型互联网项目
mybatis环境搭建
1.创建项目
2.下载jar包
3.jar包资源拿到项目中,add as lib...
核心jar包,依赖jar包,数据库的驱动jar包
4.定义sql映射文件:定义要执行的sql语句
5.java 类中进行测试
1)、加载核心配置文件
2)、构建工厂SqlSessionFactory
3)、获取会话
4)、执行sql,得到结果 selectList("命名空间.id")
5)、处理结果
6)、关闭会话
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> <!-- 环境配置 default : 要使用的环境的id值 --> <environments default="ev"> <!--environment : 一个环境的配置 id: 当前环境的唯一标识 --> <environment id="ev"> <!--transactionManager 事务管理器 type="JDBC" :选择与jdbc相同的事务管理机制 --> <transactionManager type="JDBC"/> <!--数据源配置 type="POOLED" : 通过数据库连接池管理连接--> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@localhost:1521:XE"/> <property name="username" value="SCOTT"/> <property name="password" value="TIGER"/> </dataSource> </environment> </environments> <!--sql映射配置加载 : 定义sql语句的配置文件--> <mappers> <mapper resource="com/yjxxt/mappers/DeptMapper.xml"/> </mappers> </configuration>
Dept:
package com.yjxxt.entity; import java.util.Objects; public class Dept { private int deptno; private String dname; private String loc; public Dept() { } public Dept(int deptno, String dname, String loc) { this.deptno = deptno; this.dname = dname; this.loc = loc; } public int getDeptno() { return deptno; } public void setDeptno(int deptno) { this.deptno = deptno; } public String getDname() { return dname; } public void setDname(String dname) { this.dname = dname; } public String getLoc() { return loc; } public void setLoc(String loc) { this.loc = loc; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Dept dept = (Dept) o; return deptno == dept.deptno && Objects.equals(dname, dept.dname) && Objects.equals(loc, dept.loc); } @Override public int hashCode() { return Objects.hash(deptno, dname, loc); } @Override public String toString() { return "Dept{" + "deptno=" + deptno + ", dname='" + dname + '\'' + ", loc='" + loc + '\'' + '}'; } }
DeptMpapper.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 命名空间 -> 是sql映射文件的唯一标识
1) 不能重复,随便写->不推荐
2) 建议设置为当前的表名.文件名(不加后缀)
-->
<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!--
select 定义查询语句
标签对中定义查询语句
id : sql语句的唯一标识
resultType : 结果类型
parameterType : 入参类型
-->
<select id="queryAll" resultType="com.yjxxt.entity.Dept" >
select * from dept
</select>
</mapper>
测试类:
public class Class001_Dept { public static void main(String[] args) throws IOException { //1.加载mybatis的核心配置文件 InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); //2.构建SqlSessionFactory SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); //3.根据工厂构建回话 SqlSession session = factory.openSession(); //4.执行sql,得到结果 //selectList("命名空间.id") List<Dept> list = session.selectList("com.yjxxt.mappers.DeptMapper.queryAll"); //5.处理结果 list.forEach(System.out::println); //5.关闭回话 session.close(); } }
三个常用的查询方法 : selectOne() 执行指定sql,得到一个结果 selectList() 执行指定sql,得到一个list集合,如果没查到,返回List中没有数据,但是不是null selectMap() 执行指定sql,得到一个Map集合,如果没查到,返回空map
//selectList("命名空间.id") //selectList("命名空间.id",sql语句的实参) List<Dept> list = session.selectList("com.yjxxt.mappers.DeptMapper.queryAll"); //session.selectOne("命名空间.id"); //session.selectOne("命名空间.id",sql语句的实参); Dept dept = session.selectOne("com.yjxxt.mappers.DeptMapper.queryDeptByNo",20); //session.selectMap("命名空间.id","作为key的字段名") //session.selectMap("命名空间.id",sql语句的实参,"作为key的字段名") Map<String,Dept> map = session.selectMap("com.yjxxt.mappers.DeptMapper.queryAll","dname");
<!-- 加载外部的properties文件 --> <properties resource="db.properties" /> <!--配置别名,别名不区分大小写--> <typeAliases> <!--<typeAlias type="com.yjxxt.entity.Dept" alias="Dept"/>--> <package name="com.yjxxt.entity"/> <!--为包下所有的javabean类添加别名,默认表名,不区分大小写--> </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"> <!--根元素: 核心配置--> <configuration> <!-- 加载外部的properties文件 --> <properties resource="db.properties" /> <!--配置别名,别名不区分大小写--> <typeAliases> <!--<typeAlias type="com.yjxxt.entity.Dept" alias="Dept"/>--> <package name="com.yjxxt.entity"/> <!--为包下所有的javabean类添加别名,默认表名,不区分大小写--> </typeAliases> <!-- 环境配置 default : 要使用的环境的id值 --> <environments default="ev"> <!--environment : 一个环境的配置 id: 当前环境的唯一标识 --> <environment id="ev"> <!--transactionManager 事务管理器 type="JDBC" :选择与jdbc相同的事务管理机制 --> <transactionManager type="JDBC"/> <!--数据源配置 type="POOLED" : 通过数据库连接池管理连接--> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!--sql映射配置加载 : 定义sql语句的配置文件--> <mappers> <mapper resource="com/yjxxt/mappers/DeptMapper.xml"/> </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"> <!-- 映射配置: namespace 命名空间 -> 是sql映射文件的唯一标识 1) 不能重复,随便写->不推荐 2) 建议设置为当前的表名.文件名(不加后缀) --> <mapper namespace="com.yjxxt.mappers.DeptMapper"> <!-- select 定义查询语句 标签对中定义查询语句 id : sql语句的唯一标识 resultType : 结果类型 : 基本数据类型|包装类 String Date Javabean List Map parameterType : 入参类型 : 基本数据类型|包装类 String Date Javabean 数组 List Map --> <select id="queryAll" resultType="dept" > select * from dept </select> <!--根据部门编号查询部门对象--> <select id="queryDeptByNo" parameterType="_int" resultType="Dept"> select * from dept where deptno = #{deptno} </select> </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.yjxxt.mappers.EmpMapper"> <!-- 入参类型: 基本数据类型 包装类 String Date Javabean 数组 List Map --> <!--String : 根据员工想命名查询员工数据--> <select id="queryEmpByName" resultType="Emp" parameterType="string"> select * from emp where ename = #{haha} </select> <!--Date : 根据员工的入职日期查询员工信息--> <select id="queryEmpByDate" parameterType="date" resultType="emp"> select * from emp where hiredate = #{0} </select> <!--JAVABEAN : 根据员工姓名,员工部门编号同时查询员工信息--> <select id="queryEmpByNameDeptno" parameterType="emp" resultType="emp"> select * from emp where ename=#{ename} and deptno = #{deptno} /*如果参数为javabean对象,占位符的名字需要与对应属性名保持一致*/ </select> <!--数组|list : 根据员工编号查询多个员工数据--> <select id="queryEmpByEmpnoSome" resultType="emp"> select * from emp where empno in <foreach collection="array" item="item" open="(" close=")" separator=","> #{item} </foreach> </select> <!--Map : 查询薪资>1500或者部门在30部门的员工信息--> <select id="queryEmpBySalDeptno" resultType="emp" parameterType="map"> select * from emp where sal> #{sal} or deptno = #{deptno} /*如果入参为map,占位符的名字要对象键值对的key,根据key获取value*/ </select> </mapper>
package com.yjxxt.test; import com.yjxxt.pojo.Emp; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; //测试入参类型 public class Class001_EmpTest { public static void main(String[] args) { //1.获取回话 SqlSession session = null; try { session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession(); //2.执行sql //String 根据员工想命名查询员工数据 List<Emp> list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByName","SMITH"); list.forEach(System.out::println); System.out.println("--------------------------------"); //Date 根据员工的入职日期查询员工信息 1981/12/3 Date date = new SimpleDateFormat("yyyy/MM/dd").parse("1981/12/3"); List<Emp> list2 = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByDate",date); list2.forEach(System.out::println); System.out.println("--------------------------------"); //JAVABEAN : 根据员工姓名,员工部门编号同时查询员工信息 Emp emp = new Emp(); emp.setEname("SMITH"); emp.setDeptno(20); Emp e = session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpByNameDeptno",emp); System.out.println(e); System.out.println("--------------------------------"); //数组|list : 根据员工编号查询多个员工数据 Map<Integer,Emp> map = session.selectMap("com.yjxxt.mappers.EmpMapper.queryEmpByEmpnoSome",new int[]{7369,7902},"empno"); System.out.println(map); System.out.println("--------------------------------"); //Map : 查询薪资>1500或者部门在30部门的员工信息 List<Emp> list3 = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpBySalDeptno",Map.of("sal",1500,"deptno",30)); list3.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } finally { //3.关闭回话 if(session!=null){ session.close(); } } } }
增删改更新操作
<?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.yjxxt.mappers.EmpMapper2"> <!--增删改默认结果类型为影响行数--> <insert id="addEmp" parameterType="emp"> insert into emp(empno,ename,sal,deptno) values(#{empno},#{ename},#{sal},#{deptno}) </insert> <update id="updateEnameByEmpno" parameterType="Emp"> update emp set ename = #{ename} where empno = #{empno} </update> <delete id="deleteEmpSome"> delete from emp where empno in( <foreach collection="list" item="item" separator=","> #{item} </foreach> ) </delete> </mapper>
//测试增删改更新操作 public class Class002_EmpTest { public static void main(String[] args) { //1.获取回话 SqlSession session = null; try { session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession(); /*openSession(true) 自动提交事务,默认手动提交*/ //2.执行sql //insert Emp emp = new Emp(); emp.setEmpno(9999); emp.setEname("胡歌"); emp.setSal(2000); emp.setDeptno(40); /*int rows = session.insert("com.yjxxt.mappers.EmpMapper2.addEmp",emp); if(rows>0){ session.commit(); //事务提交 }else{ session.rollback(); //事务回滚 } System.out.println(rows>0?"跟新成功":"更新失败");*/ //update /*emp.setEname("彭于晏"); int rows = session.update("com.yjxxt.mappers.EmpMapper2.updateEnameByEmpno",emp); if(rows>0){ session.commit(); System.out.println("更新成功"); }else{ session.rollback(); System.out.println("更新失败"); }*/ //delete int rows = session.delete("com.yjxxt.mappers.EmpMapper2.deleteEmpSome",List.of(9999,7999)); if(rows>0){ session.commit(); System.out.println("更新成功"); }else{ session.rollback(); System.out.println("更新失败"); } } catch (IOException e) { e.printStackTrace(); } finally { //3.关闭回话 if(session!=null){ session.close(); } } } }
结果类型
<?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"> <!--测试结果类型 : 基本数据类型 | 包装类 javabean date String List Map List<Map> 如果结果为 集合,添加集合的泛型类型 Map当结果类型为map,把一条数据的每一个字段作为map中的一个键值对,一个map展示一条数据 List<Map>如果有多条数据,每一个调数据作为一个map放入list中 --> <mapper namespace="com.yjxxt.mappers.EmpMapper3"> <!--double : 根据员工编号查询员工薪资--> <select id="querySalByNo" parameterType="int" resultType="double"> select sal from emp where empno = #{empno} </select> <!--date : 根据员工信息查询员工的入职日期--> <select id="queryDateByName" parameterType="string" resultType="date"> select hiredate from emp where ename = #{name} </select> <!--map : 根据员工的编号,查询员工信息--> <select id="queryMapByNo" parameterType="int" resultType="map"> select * from emp where empno = #{empno} </select> <!--List<Map> : 根据员工姓名模糊匹配员工数据--> <select id="queryListMap" parameterType="string" resultType="map"> select * from emp where ename like '%'||#{ename}||'%' </select> </mapper>
//测试结果类型 public class Class003_EmpTest { public static void main(String[] args) { //1.获取回话 SqlSession session = null; try { session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession(); /*openSession(true) 自动提交事务,默认手动提交*/ //2.执行sql //double : 根据员工编号查询员工薪资 double sal = session.selectOne("com.yjxxt.mappers.EmpMapper3.querySalByNo",7369); System.out.println(sal); //date : 根据员工信息查询员工的入职日期 Date date = session.selectOne("com.yjxxt.mappers.EmpMapper3.queryDateByName","KING"); System.out.println(date); // <!--map : 根据员工的编号,查询员工信息--> Map<String,Object> map = session.selectOne("com.yjxxt.mappers.EmpMapper3.queryMapByNo",7369); System.out.println(map); System.out.println("---------------------------"); /*List<Map> : 根据员工姓名模糊匹配员工数据*/ List<Map<String,Object>> listMap = session.selectList("com.yjxxt.mappers.EmpMapper3.queryListMap","A"); listMap.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } finally { //3.关闭回话 if(session!=null){ session.close(); } } } }
接口绑定方案 封装: sqlSession回话的封装工具类 public class SessionUtils { private static SqlSessionFactory factory = null; static{ try { factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")); } catch (IOException e) { e.printStackTrace(); } } //获取回话 public static SqlSession getSession(){ SqlSession session = null; if(factory!=null){ session = factory.openSession(true); } return session; } }
测试接口绑定方案: 1.定义接口 定义抽象方法(业务) 2.与接口相关联的sql映射文件 3.测试使用 public interface EmpMapper { //查询所有的员工数据 public List<Emp> queryAllEmp(); }
<?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映射文件:
1.接口与sql映射文件在同一个包中
2.接口与sql映射文件同名
3.sql映射文件的命名空间namespace,要求定义为接口的包名.接口名(权限定名)
4.sql标签的id属性值定义为与其对应的接口中抽象方法名
5.sql的返回值与参数要求与抽象方法的返回值与参数保持一致
-->
<mapper namespace="com.yjxxt.mappers.EmpMapper">
<!--查询所有的员工数据-->
<select id="queryAllEmp" resultType="emp">
select * from emp
</select>
</mapper>
/* 测试接口绑定方案的基本使用 */ public class Class001_interface_bind { public static void main(String[] args) { //1.获取回话 SqlSession session = SessionUtils.getSession(); //2.获取接口的实现类对象 //接口多态 EmpMapper mapper = session.getMapper(EmpMapper.class); //3.调用功能 List<Emp> list = mapper.queryAllEmp(); list.forEach(System.out::println); //4.关闭回话 session.close(); } }