官网: https://mybatis.org/mybatis-3/zh/index.html
Mybatis框架介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了 google code,并且改名为MyBatis 。2013年11月迁移到Github。 iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框 架包括SQL Maps和Data Access Objects(DAO) MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的 JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和 原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
简单概括:
更加简化jdbc代码,简化持久层,sql语句从代码中分离,利用反射,将表中数据与java bean 属性一一 映射 即 ORM(Object Relational Mapping 对象关系映射)
Mybatis功能架构图
从上面我们可以看到mybatis的功能架构分为三层: API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层接收到调用请 求就会调用数据处理层来完成具体的数据处理。 数据处理层:负责具体的SQL查 找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据 调用的请求完成一次数据库操作。 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用 的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
Mybatis环境搭建
1.新建项目,配置jar包
mybatis核心jar包
mybatis依赖的jar包
数据库的驱动包
2.编写核心配置文件
3.编写SQl映射文件,编写实体类
4.测试
配置jar包
编写核心配置文件
<?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>
<!--
用于指明使用哪一个开发环境
default : 用于指定使用的环境的id属性值
-->
<environments default="ev">
<!-- 用户配置开发环境 id: 环境的唯一标识 -->
<environment id="ev">
<!--
事务管理器
JBDC : 表示采用JDBC一样的事务管理方式
-->
<transactionManager type="JDBC"/>
<!--
用于配置数据库连接吃和数据库连接参数
POOLED : 表示mybatis采用连接池技术
-->
<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映射文件配置 -->
<mappers>
<!-- 指明SQL映射文件路径 resource : 包路径 com/.../xxxMapper.xml-->
<mapper resource="com/yjxxt/mappers/DeptMapper.xml"/>
</mappers>
</configuration>
编写sql映射文件,编写实体类
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">
<!--
跟标签mapper
namespace: 命名空间
要求:唯一的,SQL映射文件唯一标识
定义方式:
1.随意定义,只要不重复即可,不推荐,不便于后期维护
2.推荐使用包名.文件名
-->
<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!--
查询标签: select 用于编写查询语句
id : 当前文件中保证唯一
resultType : 结果的类型
parameterType : 入参类型
-->
<select id="queryDept" resultType="com.yjxxt.pojo.Dept">
select * from dept
</select>
<!--根据部门编号查询部门信息-->
<select id="quaryDeptById" resultType="com.yjxxt.pojo.Dept" parameterType="int">
select * from dept where deptno=#{ID}
</select>
<!--根据部门位置查询部门信息-->
<select id="quaryDeptByLoc" resultType="com.yjxxt.pojo.Dept" parameterType="String">
select * from dept where loc=#{loc}
</select>
</mapper>
实体类
package com.yjxxt.pojo;
public class Dept {
private int deptno;
private String dname;
private String loc;
public Dept(int deptno, String dname, String loc) {
this.deptno = deptno;
this.dname = dname;
this.loc = loc;
}
public Dept() {
}
/**
* 获取
* @return deptno
*/
public int getDeptno() {
return deptno;
}
/**
* 设置
* @param deptno
*/
public void setDeptno(int deptno) {
this.deptno = deptno;
}
/**
* 获取
* @return dname
*/
public String getDname() {
return dname;
}
/**
* 设置
* @param dname
*/
public void setDname(String dname) {
this.dname = dname;
}
/**
* 获取
* @return loc
*/
public String getLoc() {
return loc;
}
/**
* 设置
* @param loc
*/
public void setLoc(String loc) {
this.loc = loc;
}
public String toString() {
return "Dept{deptno = " + deptno + ", dname = " + dname + ", loc = " + loc + "}";
}
}
测试
package com.yjxxt.test;
import com.yjxxt.pojo.Dept;
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;
import java.util.List;
import java.util.Map;
public class Class002_Method {
public static void main(String[] args) throws IOException {
//1.加载核心文件
InputStream is= Resources.getResourceAsStream("mybatis.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.queryDept");
//测试使用selectOne("命名空间.id",入参)
Dept dept=session.selectOne("com.yjxxt.mappers.DeptMapper.quaryDeptById",10);
System.out.println(dept);
System.out.println("-----------------------");
//测试selectList("命名空间.id");
List<Dept> list2=session.selectList("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK");
list2.forEach(System.out::println);
System.out.println("--------------------------");
//selectMap("命名空间.id","作为key的字段名")
//selectMap("命名空间.id",入参,"作为key的字段名")
Map<Integer,Dept> map =session.selectMap("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK","deptno");
System.out.println(map);
//5.处理结果
System.out.println("-------------------");
list.forEach(System.out::println);
//6.关闭会话
session.close();
}
}
运行结果:
数据库查询结果:
Log4j日志
在apache网站: jakarta.apache.org/log4j 可以免费下载到Log4j最新版本的软件包。
日志级别
分为五个级别: DEBUG(人为调试信息)、INFO(普通信息)、WARN(警告)、ERROR(错误)和FATAL(系统错误) 这五个级别是有顺序的,DEBUG < INFO < WARN < ERROR < FATAL,分别用来指定这条日志信息的重 要程度,明白这一点很重要,Log4j有一个规则:只输出级别不低于设定级别的日志信息,Logger 级别设定为INFO,则INFO、WARN、ERROR和FATAL级别的日志信息都会输出,而级别比INFO低的 DEBUG则不会输出。
log4j使用
导包
配置文件
在src目录下创建properties配置文件,内容如下
# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=INFO, CONSOLE
# log4j.rootCategory=INFO, CONSOLE, LOGFILE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %m %c %l %d{yyyy-MM-dd HH:mm:ss}%n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:/test.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %m %l%n
日志格式输出
进行测试
package com.yjxxt.test;
//注意要获取apache包下面的Logger类
import org.apache.log4j.Logger;
public class Class003_log4j {
public static void main(String[] args) {
//获取一个日志对象
Logger logger = Logger.getLogger(Class003_log4j.class);
//测试武功和日志级别
logger.fatal("致命的。。系统错误");
logger.error("错误。。。。");
logger.warn("警告。。。。");
logger.info("日志信息。。。。");
logger.debug("用户调试信息。。。。");
}
}
输出结果:
配置文件中写明了info,故只显示info及以上的警告级别的日志信息
Mybatis对Log4j的支持
测试代码
package com.yjxxt.test;
import com.yjxxt.pojo.Dept;
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;
import java.util.List;
public class Class001_Dept {
public static void main(String[] args) throws IOException {
//1.加载核心文件
InputStream is= Resources.getResourceAsStream("mybatis.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.queryDept");
//5.处理结果
list.forEach(System.out::println);
//6.关闭会话
session.close();
}
}
通过setting标签开始对log4j的支持
通过查看mybatis官网,对log4j的支持,配置在mybatis的核心配置文件中
通过查看configuration查看setting配置位置
修改后的mybatis.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>
<!-- settings标签 -->
<settings>
<!-- 设置MyBatis使用log4j日志支持 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--
用于指明使用哪一个开发环境
default : 用于指定使用的环境的id属性值
-->
<environments default="ev">
<!-- 用户配置开发环境 id: 环境的唯一标识 -->
<environment id="ev">
<!--
事务管理器
JBDC : 表示采用JDBC一样的事务管理方式
-->
<transactionManager type="JDBC"/>
<!--
用于配置数据库连接吃和数据库连接参数
POOLED : 表示mybatis采用连接池技术
-->
<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映射文件配置 -->
<mappers>
<!-- 指明SQL映射文件路径 resource : 包路径 com/.../xxxMapper.xml-->
<mapper resource="com/yjxxt/mappers/DeptMapper.xml"/>
</mappers>
</configuration>
不同日志级别下的输出
log4j.rootCategory=DEBUG, CONSOLE
log4j.rootCategory=INFO, CONSOLE
注意:上诉两种级别设定都不能满足,保留SQl语句的信息的同时,不显示一些非重要语句
单独设置SQL语句输出级别为DEBUG
a.注释单个SQL语句为DEBUG
修改 log4j.properties
#单独设置SQL语句输出级别为DEBUG
#方法级别设置(SQL语句--每一个SQL语句其实就是一个方法
log4j.logger.com.yjxxt.mappers.DeptMapper.queryDept=DEBUG
输出结果:保留了SQL语句的输出
b.类级别的等级设置
#修改 log4j.properties
#类级别设置(SQL文件
log4j.logger.com.yjxxt.mappers.DeptMapper=DEBUG
测试代码:
public class Class002_Method {
public static void main(String[] args) throws IOException {
//1.加载核心文件
InputStream is= Resources.getResourceAsStream("mybatis.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.queryDept");
//测试使用selectOne("命名空间.id",入参)
Dept dept=session.selectOne("com.yjxxt.mappers.DeptMapper.quaryDeptById",10);
System.out.println(dept);
System.out.println("-----------------------");
//测试selectList("命名空间.id");
List<Dept> list2=session.selectList("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK");
list2.forEach(System.out::println);
System.out.println("--------------------------");
//selectMap("命名空间.id","作为key的字段名")
//selectMap("命名空间.id",入参,"作为key的字段名")
Map<Integer,Dept> map =session.selectMap("com.yjxxt.mappers.DeptMapper.quaryDeptByLoc","NEW YORK","deptno");
System.out.println(map);
//5.处理结果
System.out.println("-------------------");
list.forEach(System.out::println);
//6.关闭会话
session.close();
}
}
c.包级别下的设置
#包级别设置
log4j.logger.com.yjxxt.mappers=DEBUG
通过properties标签实现软编码
src下配置properties文件
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=SCOTT
password=TIGER
在mybatis中配置properties标签
<!-- 加载外部的properties文件 -->
<properties resource="db.properties" />
位置在settings前configuration后
使用方式
typeAliases标签
用于给java类型定义别名,方便在配置文件中使用
在mybatis官网下查看
使用方式:(为com.yjxxt.pojo.Dept设置别名
<typeAliases>
<!-- <typeAlias alias="D" type="com.yjxxt.pojo.Dept"/>-->
<!-- 别名默认为类名Dept-->
<typeAlias type="com.yjxxt.pojo.Dept"/>
<!-- 为一个包中的所有类型设置别名,默认为类名不区分-->
<package name="com.yjxxt.pojo"/>
</typeAliases>
Mybatis內键别名
parameterType入参类型
如果执行的是条件查询,DML,需要在调用方法的时候传递参数,此时, 可以在sql标签中通过 parameterType属性指定参数的类型(别名|权限定名). 而在sql语句,通过#{}的方式获取参数
基本数据类型|包装类
<!-- 基本数据类型|包装类 根据员工编号查看员工信息-->
<select id="queryEmpId" parameterType="int" resultType="emp">
select * from emp where empno=#{empno}
</select>
// 基本数据类型|包装类
Emp emp=session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpId",7369);
System.out.println(emp);
包装类Date
<!-- Date 根据员工入职日期查看员工信息-->
<select id="queryEmpByDate" parameterType="Date" resultType="emp">
select * from emp where hiredate=#{hiredate}
</select>
System.out.println("======Date 根据员工入职日期查看员工信息===========");
list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByDate",new SimpleDateFormat("yyyy/MM/dd").parse("1981/12/3"));
list.forEach(System.out::println);
String
<!-- String 根据员工姓名查看员工信息-->
<select id="queryEmpByName" parameterType="String" resultType="emp">
select * from emp where ename=#{ename}
</select>
System.out.println("======String 根据员工姓名查看员工信息===========");
List<Emp> list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByName","SMITH");
list.forEach(System.out::println);
Map
<!-- Map 根据员工薪资与员工的部门编号查看员工信息-->
<select id="queryEmpBySalDeptno" parameterType="map" resultType="emp">
select * from emp where sal=#{sal} or deptno=${deptno}
</select>
System.out.println("======Map 根据员工薪资与员工的部门编号查看员工信息===========");
//创建一个员工实例
Map map=new HashMap<>();
map.put("deptno",10);
map.put("sal",1500);
list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpBySalDeptno",map);
list.forEach(System.out::println);
数组List
<!-- 数组 根据员工薪资与员工的部门编号查看员工信息-->
<select id="queryEmpByNoSome" resultType="emp">
select * from emp where empno in(
<foreach collection="array" separator="," item="item">
#{item}
</foreach>
)
</select>
System.out.println("======数组 根据员工薪资与员工的部门编号查看员工信息===========");
//创建一个员工实例
int[] arr={7369,7499,9999};
list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByNoSome",arr);
list.forEach(System.out::println);
//3.关闭会话
session.close();
JavaBean
<!-- JavaBean 根据员工姓名与员工薪资查看员工信息-->
<!-- sql 中的占位符的名字匹配入参对象的属性名,根据属性名匹配属性值-->
<select id="queryEmpByNameSal" parameterType="emp" resultType="emp">
select * from emp where ename=#{ename} and sal=${sal}
</select>
System.out.println("======JavaBean 根据员工姓名和薪资查看员工信息===========");
//创建一个员工实例
Emp e=new Emp();
e.setDeptno(8888);
e.setEname("SMITH");
e.setSal(800);
list=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByNameSal",e);
list.forEach(System.out::println);
工具类的封装
package com.yjxxt.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 SessionUtils {
private static SqlSessionFactory factory=null;
static{
try {
factory =new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSession(){
SqlSession session=null;
if(factory!=null){
session=factory.openSession();
}
return session;
}
}
测试代码
public class Class003_Test {
public static void main(String[] args) throws IOException {
// //1.加载核心文件
// InputStream is= Resources.getResourceAsStream("mybatis.xml");
// //2.构建SqlSessionFactory实例
// SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
//3.获取会话
SqlSession session=SessionUtils.getSession();
//4.执行Sql
//selectList("命名空间.id");
List<Dept> list=session.selectList("com.yjxxt.mappers.DeptMapper.queryDept");
//5.处理结果
list.forEach(System.out::println);
//6.关闭会话
session.close();
}
}
运行结果:
事务
1. 事务是数据库操作的最小单位,有着ACID的特性,应该保证一个事务下的多条SQL语句要么都成功,要 么都失败.
2. Mybatis中配置了事务管理器,type属性设置JDBC,表示Mybatis采用和原生JDBC相同的事务管理机 制
3.在Myabatis执行操作的开始,将自动提交功能关闭了,需要我们在执行DML操作时候,手动提交设置| 设置自动提交
创建会话的时候设置自动提交
在包装的工具类里面,创建会话的时候就设置自动提交(通过参数true
public static SqlSession getSession(){
SqlSession session=null;
if(factory!=null){
//()手动提交 true自动提交
//session=factory.openSession(true);
session=factory.openSession();
}
return session;
}
在测试代码中设置手动提交
int rows=session.delete("com.yjxxt.mappers.DeptMapper.deleteDept",70);
if(rows>0){
//添加成功,手动提交
session.commit();
}else{
//添加失败,回滚
session.rollback();
}
结果类型
注意返回List集合的时候要返回泛型的类型
数据库查询结果
基本数据类型|包装类
<!-- 基本数据类型|包装类 根据员工编号查看员工薪资-->
<select id="querySalByNo" parameterType="int" resultType="double">
select sal from emp where empno=#{empno}
</select>
System.out.println("<!-- 基本数据类型|包装类 根据员工编号查看员工薪资-->");
double d=session.selectOne("com.yjxxt.mappers.EmpMapper.querySalByNo",7369);
System.out.println(d);
String
<!-- String 根据员工编号查看员工姓名-->
<select id="queryNameByNo" parameterType="int" resultType="String">
select ename from emp where empno=#{empno}
</select>
System.out.println("<!-- String 根据员工编号查看员工姓名-->");
String str=session.selectOne("com.yjxxt.mappers.EmpMapper.queryNameByNo",7369);
System.out.println(str);
Date
<!-- Date 根据员工编号查询员工入职日期-->
<select id="queryDateByNo" parameterType="int" resultType="Date">
select hiredate from emp where empno=#{empno}
</select>
System.out.println("<!-- Date 根据员工编号查询员工入职日期-->");
Date date=session.selectOne("com.yjxxt.mappers.EmpMapper.queryDateByNo",7369);
System.out.println(date);
Map
<!-- Map 根据员工编号,查询员工信息-->
<select id="queryEmpByNo" parameterType="int" resultType="Map">
select * from emp where empno=#{empno}
</select>
System.out.println("<!-- Map 根据员工编号,查询员工信息-->");
Map<String,Object> map=session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpByNo",7369);
System.out.println(map);
List<Map>
<!-- List<Map> 根据员工姓名模糊查询-->
<select id="queryEmpByNoLike" parameterType="String" resultType="map">
select * from emp where ename like '%'||#{ename}||'%'
</select>
System.out.println("<!-- List<Map> 根据员工姓名模糊查询-->");
List<Map<String,Object>> list1=session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByNoLike","A");
list1.forEach(System.out::println);
接口绑定方案
Mybatis
1.定义接口的实现类
2.重写接口当中的抽象方法
3.找到相应的SQL语句
4.创建实现类对象
Myabtis中,提供了一套接口绑定方案,程序员可以提供一个接口,然后提供一个与接口所对应的 mapper.xml文件
Myabaits会自动讲接口与xml文件进行绑定,实际上就是Mybatis互根据接口和对应的xml文件创建一个接 口的实现类,换言之,就是可以得到接口实现类的一个对象,方便方法的调用
实现步骤:
1.定义接口,定义抽象功能
2.定义与接口绑定的SQL文件,定义SQL语句,按照要求进行定义
3.核心配置文件中通过Mapper扫描接口
4.在java代码中通过获取接口实现类对象调用功能
定义接口,定义抽象功能
/*
接口绑定方案下的接口
*/
public interface DeptMapper {
//查询所有的部门信息
public List<Dept> qureyAll();
}
定义与接口绑定的SQL文件,定义SQL语句,按照要求进行定义
定义要求
1.接口与SQl映射文件名要保持一致,并且放在同一个包下
2.SQl映射文件名的命名空间namespaces定义为与之绑定的接口包名.类名
3.SQl标签的ID属性值要与接口当中所对应的抽象方法的方法名保持一致
4.SQl语句的参数与返回值要与对应的抽象方法的参数和返回值保持一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yjxxt.mappers.DeptMapper">
<select id="qureyAll" resultType="Dept">
select * from Dept
</select>
</mapper>
核心配置文件中通过Mapper扫描接口
<!-- 扫描接口,接口绑定方案-->
<mappers>
<mapper class="com.yjxxt.mappers.DeptMapper"/>
</mappers>
4.在java代码中通过获取接口实现类对象调用功能
public class Class001_InterfaceBind {
public static void main(String[] args) {
//1获取会话
SqlSession session= SessionUtils.getSession();
//2.获取接口实现类对象--》指定哪一个接口
DeptMapper mapper =session.getMapper(DeptMapper.class);
//3.调用方法
List<Dept> list=mapper.qureyAll();
list.forEach(System.out::println);
//4.关闭会话
session.close();
}
}
通过接口绑定解决多参数传递方案
测试类
public class Class002_Param {
public static void main(String[] args) {
//1获取会话
SqlSession session= SessionUtils.getSession();
//2.获取接口实现类对象--》指定哪一个接口
EmpMapper mapper =session.getMapper(EmpMapper.class);
//3.调用方法
System.out.println("<!--一个参数 根据部门编号查看员工信息-->");
Emp emp=mapper.queryEmpById(7369);
System.out.println(emp);
//多个参数
System.out.println("<!--多个参数 根据薪资与部门一起查询-->");
List<Emp> list=mapper.queryEmpSalDeptno(1500,30);
list.forEach(System.out::println);
//4.关闭会话
session.close();
}
}
方法一 使用args 或者param
映射文件
<!--多个参数 根据薪资与部门一起查询-->
<select id="queryEmpSalDeptno" resultType="Emp">
select * from emp where sal>#{arg0} and deptno=#{arg1}
select * from emp where sal>#{param1} and deptno=#{param2}
</select>
对应的接口
//根据薪资与部门一起查询
List<Emp> queryEmpSalDeptno(@Param("sal") double sal, int deptno);
方法二 使用注解@Param
映射文件
select * from emp where sal>#{sal} and deptno=#{deptno}
对应的接口
//根据薪资与部门一起查询
List<Emp> queryEmpSalDeptno(@Param("sal") double sal, @Param("deptno") int deptno);
运行结果:
接口代理开发(CRUD)
insert
<!-- insert 插入一个部门信息-->
<insert id="insertDept" parameterType="dept">
insert into dept values(#{deptno},#{dname},#{loc})
</insert>
System.out.println("<!--一个参数 根据部门编号查看员工信息-->");
int rows=mapper.insertDept(new Dept(66,"六部","上海"));
System.out.println(rows>0?"操作成功":"失败");
数据库查询结果:
update
<!-- update 根据部门编号修改部门名称-->
<update id="updateDept" >
update dept set dname =#{dname} where deptno=#{deptno}
</update>
System.out.println("<!-- update 根据部门编号修改部门名称-->");
int rows=mapper.updateDept(66,"liu");
System.out.println(rows);
delete
<!--delete 根据部门编号删除部门信息-->
<delete id="deleteDept" parameterType="int">
delete from dept where deptno=#{deptno}
</delete>
System.out.println("<!--delete 根据部门编号删除部门信息-->");
int rows=mapper.deleteDept(66);
System.out.println(rows);
动态Sql
通过条件SQl语句随之发生改变
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同 条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个 列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。 使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显 著地提升了这一特性的易用性。
if ( 相当于if单选择
用于进行条件判断, test 属性用于指定判断条件. 为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条 件
where
choose...when...otherwise(相当于Switch条件判断
set
trim
bind
foreach
sql_include
Mybatis缓存机制
列名与属性名不一致问题
如果查询时使用 resultType 属性, 表示采用 MyBatis 的Auto-Mapping(自动映射)机制, 即相同的列名和 属性名会自动匹配. 因此, 当数据库表的列名和类的属性名不一致时, 会导致查不到数据
//Dept实体类
/*
测试字段名与属性名不一致的问题
*/
public class Dept {
private int no;
private String name;
private String loc;
public Dept(int deptno, String dname, String loc) {
this.no = deptno;
this.name = dname;
this.loc = loc;
}
public Dept() {
}
@Override
public String toString() {
return "Dept{" +
"no=" + no +
", name='" + name + '\'' +
", loc='" + loc + '\'' +
'}';
}
}
<select id="qureyAll" resultType="Dept">
select deptno,dname,loc from Dept
</select>
解决办法:
使用resultMap标签
自定义表与javaBean类型的映射情况
不同字段名必须手动设置映射关系
同名的字段名可以不设置,默认会根据自动映射机制找同名
<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!-- 自定义结果映射关系-->
<resultMap id="deptMap" type="Dept">
<!-- 主键字段与属性的映射关系-->
<id column="deptno" property="no"/>
<!-- 非主键字段与属性的映射关系-->
<result column="dname" property="name"/>
</resultMap>
<select id="qureyAll" resultMap="deptMap" >
select deptno,dname,loc from Dept
</select>
</mapper>
为字段起别名
要求字段别名与类型对应的属性名保持一致
<!-- 用别名实现-->
<select id="qureyAll" resultType="Dept" >
select deptno no,dname name,loc from Dept
</select>
resultMap 的关联方式实现多表查询(一对一|多对一)
1.多表查询所有员工信息和部门信息
<mapper namespace="com.yjxxt.mappers.EmpMapper">
<!-- 自定义结果集中的字段与javaBean中属性的映射关系-->
<resultMap id="EmpDept" type="Emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="sal" property="sal"/>
<result column="job" property="job"/>
<result column="comm" property="comm"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="deptno" property="deptno"/>
<!-- association 定义javabean类型属性的映射关系 -->
<association property="dept" javaType="Dept">
<id column="deptno" property="no"></id>
<result column="dname" property="name"></result>
<result column="loc" property="loc"></result>
</association>
</resultMap>
<select id="queryEmpDept" resultMap="EmpDept">
select empno,ename,job,mgr,hiredate,sal,comm,emp.deptno,dname,loc from emp join dept on emp.deptno=dept.deptno
</select>
</mapper>
在Emp实体类中定义
//定义一个属性表示部门信息
private Dept dept;
测试类:
public class Class002_EmpDeptTest {
public static void main(String[] args) {
//1获取会话
SqlSession session= SessionUtils.getSession();
//2.获取接口实现类对象--》指定哪一个接口
EmpMapper mapper =session.getMapper(EmpMapper.class);
//3.调用方法
List<Emp> list=mapper.queryEmpDept();
list.forEach(System.out::println);
//4.关闭会话
session.close();
}
}
运行结果:
2.查询一对多 查询每个部门和这个部门里面的员工信息
<mapper namespace="com.yjxxt.mappers.DeptMapper">
<!-- 自定义结果映射关系-->
<resultMap id="deptMap" type="Dept">
<!-- 主键字段与属性的映射关系-->
<id column="deptno" property="no"/>
<!-- 非主键字段与属性的映射关系-->
<result column="dname" property="name"/>
<result column="loc" property="loc"></result>
<!-- 当类中的属性为List集合,使用collection标签定义-->
<collection property="empList" javaType="List"
ofType="Emp">
<id column="empno" property="empno"/>
<result column="ename" property="ename"/>
<result column="sal" property="sal"/>
<result column="job" property="job"/>
<result column="comm" property="comm"/>
<result column="mgr" property="mgr"/>
<result column="hiredate" property="hiredate"/>
<result column="deptno" property="deptno"/>
</collection>
</resultMap>
<select id="qureyAll" resultMap="deptMap" >
select dept.deptno,dname,loc,empno,ename,job,mgr,hiredate,sal,comm from dept left join emp on emp.deptno=dept.deptno
</select>
</mapper>
public class Dept {
private int no;
private String name;
private String loc;
//定义一个集合存储该部门里面的员工信息
private List<Emp> empList;
public Dept(int deptno, String dname, String loc) {
this.no = deptno;
this.name = dname;
this.loc = loc;
}
public Dept() {
}
@Override
public String toString() {
return "Dept{" +
"no=" + no +
", name='" + name + '\'' +
", loc='" + loc + '\'' +
", empList=" + empList +
'}';
}
}
测试类:
public class Class001_InterfaceBind {
public static void main(String[] args) {
//1获取会话
SqlSession session= SessionUtils.getSession();
//2.获取接口实现类对象--》指定哪一个接口
DeptMapper mapper =session.getMapper(DeptMapper.class);
//3.调用方法
List<Dept> list=mapper.qureyAll();
list.forEach(System.out::println);
//4.关闭会话
session.close();
}
}
运行结果
Mybatis缓存机制
一级缓存
1. 默认开启. 线程级别的缓存, SqlSession 的缓存; 2. 在一个 SqlSession 生命周期中有效. SqlSession 关闭,缓存清空; 3. 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果 存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据; 4. 不同的 SqlSession 之间的缓存是相互隔离的; 5. 用一个 SqlSession, 可以通过配置使得在查询前清空缓存;flushCache="true" 6. 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。
二级缓存
1. 进程级别的缓存, SqlSessionFactory 的缓存 2. 在一个SqlSessionFactory生命周期中有效. 可以在多个SqlSession 生命中期中共享. 3. 默认关闭, 需要使用的时候, 要为某个命名空间开启二级缓存(在 mapper.xml 中配置cache).
<!-- 开启二级缓存, 要求实体类进行序列化 -->
<cache />
在核心配置文件中开启二级缓存之后,再在相应的映射文件中开启缓存 4. 由于在更新时会刷新缓存, 因此需要注意使用场合:查询频率很高, 更新频率很低时使用, 即经 常使用 select, 相对较少使用delete, insert, update。 5. 缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。但刷新缓存是刷新整个 namespace 的缓存, 也就是你 update 了一个, 则整个缓存都刷新了。 6. 最好在 「只有单表操作」 的表的 namespace 使用缓存, 而且对该表的操作都在这个 namespace 中。 否则可能会出现数据不一致的情况。