1.MyBatis:基于持久层的orm框架
Mybatis特点
属于持久层ORM框架
- 对原生JDBC的封装
- 半自动化框架
- 学习成本低,使用简单,适合做一些业务多变的互联网项目
环境搭建
1)下载资源jar包
2)项目下新建lib路径,需要的jar包放入lib路径下,选中右键add as lib..
3)编写代码程序
1.核心配置文件 : 做mybatis使用的核心基本配置
数据库的连接信息
是否使用连接池技术
SQL映射文件的扫描
----
2.SQL映射文件 : 定义SQL语句
3.测试执行使用mybatis框架连接数据库,执行SQL语句,得到结果
2.Mybatis配置文件
mybatis提供两种配置文件, 核心配置文件 mybatisconfig.xml|mybatis.xml 与 SQL映射文件
mapper.xml
核心配置文件添加
是一个xml文件,命名无要求,位置无要求,一般成为mybatis.xml,放在src路径下
1.1. dtd
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
1.2. 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>
<!--
用于指明使用哪一个开发环境
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/UserMapper.xml"/>
</mappers>
</configuration>
Mybatis SQL映射文件
在Mybatis中,推荐使用mappers作为包名,我们只需要写一个映射配置文件就可以,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">
<!--
跟标签mapper
namespace: 命名空间
-->
<mapper namespace="com.yjxxt.mappers.UserMapper">
<!--
查询标签: select 用于编写查询语句
id : 当前文件中保证唯一
resultType : 结果的类型
parameterType : 入参类型
-->
<select id="queryAll" resultType="com.yjxxt.pojo.User">
select * from t_user
</select>
</mapper>
注意:不要忘记mybatis核心xml文件中的mapper配置
测试
public class TestUser {
public static void main(String[] args) throws IOException {
//1.加载mybatis全局核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//2.构建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂获取会话SqlSession
SqlSession session = factory.openSession();
//4.通过session调用方法执行查询
//selectList() 查到的数据返回一个list集合,没查到返回空的list
//selectList 的第一个参数为statement: 命名空间+id
List<User> list =
session.selectList("com.yjxxt.mappers.UserMapper.queryAll");
System.out.println(list);
//5.关闭会话资源
session.close();
}
}
3.Mybatis配置文件详解
1. 核心配置文件
1.configuration
配置文件的根元素,所有其他的元素都要在这个标签下使用(dtd文件规定)
2.environments default=“environment”
用于管理所有环境, 并可以指定默认使用那个环境,通过defualt属性来指定
3.environment
用来配置环境,id属性用于唯一标识当前环境
4.transactionManager type=“JDBC”
用户配置事务管理器
type属性
用来指定Mybatis采用何种方式管理事务
JDBC : 表示采用与原生JDBC一致方式管理事务
MANAGED: 表示讲事务管理交给其他容器进行, Spring
5.dataSource type=“POOLED”
用于配置数据源, 设置Myabtis是否使用连接池技术,并且配置数据库的四个连接参数
type属性:
POOLED : 表示采用连接池技术
UNPOOLED: 表示每次都会开启和关闭连接, 不采用连接池技术
JNDI : 使用其他容器提供数据源
6.property
用于配置数据库连接参数 (driver,url,username,password)
7.Mappers
用于配置扫描sql映射文件
2. SQL映射文件(mapper)
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
查询语句是 MyBatis 中最常用的元素之一(映射文件配置见代码)
1.mapper
SQL映射文件的根元素
namespace 属性
用于指定命名空间, mydatis通过namespace+id的方式用来定位sql语句,所以必须要指定namespace,通过被配置为权限定路径 包名+xml文件名(不带后缀名)
2.select
用来定义查询语句 update insert delete
id 属性
用阿里唯一表示当前sql语句,在当前的命名空间中唯一,不能重复 , 类型方法名
resultType 属性
用于设定查询返回的结果的数据类型,要写类型的权限定名(包名+类名),如果返回值的是集合类型,要定义集合的泛型类型
4.通过properties标签实现软编码
<?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>
<!--alias 设置别名-->
<!--<typeAlias type="com.yjxxt.pojo.Dept" alias="Dept"/>-->
<!--没有定义alias属性,默认别名为类型,不缺分大小写-->
<!--<typeAlias type="com.yjxxt.pojo.Dept"/>-->
<!--设置一个包下所有的类型定义别名,别名默认类名,不区分大小写-->
<package name="com.yjxxt.pojo"/>
</typeAliases>
<!--
mybatis使用环境配置
default : 选择要使用的环境
属性值定义为环境的id值
-->
<environments default="dev">
<!--environment 定义环境配置 id : 环境的唯一标识-->
<environment id="dev">
<!--transactionManager事务管理机制 : type="JDBC"选择使用JDBC项目的事务管理机制-->
<transactionManager type="JDBC"/>
<!--dataSource : 数据源配置|是否使用来连接池技术-->
<!--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映射文件-->
<mappers>
<!--一个SQL映射文件的加载 : resource指定SQL映射文件在项目中的路径-->
<mapper resource="com/yjxxt/mappers/DeptMapper.xml"/>
<mapper resource="com/yjxxt/mappers/EmpMapper.xml"/>
</mappers>
</configuration>
5.三个查询方法
- selectList(“命名空间.id”) 用户查询多条数据情况,返回一个List集合, 没有查到数据返回空集合,不是null
- selectOne(“命名空间.id”) 用于查询单条数据,返回一个数据, 如果没有查到返回null
- selectMap(“命名空间.id”,key的字段名) 用于查询多条记录情况, 返回Map集合, 需要指定那个属性作为key, sql查询结果作为value,指定的字段值作为key, 如果查不到, 返回一个空map集合,不是null
/*
测试3个查询方法
selectOne("命名空间.id") 查询一个数据,返回对应类型的一个结果,如果没有查询到返回null
selectOne("命名空间.id",Object) 第二个参数为sql语句的入参
selectList("命名空间.id") 查询多个数据,返回一个List集合,如果没有查询到返回空的List
selectList("命名空间.id",Object) 第二个参数为sql语句的入参
selectMap("命名空间.id","作为key的字段名") 查询多个数据,返回一个Map集合,如果没有查询到返回空的Map
selectMap("命名空间.id",Object,"作为key的字段名") 第二个参数为sql语句的入参,第三个参数返回Map集合中每条数据作为key的字段名
*/
public class Class002_Method {
public static void main(String[] args) throws IOException {
//1.加载XML核心配置文件
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建SqlSessionFactory实例
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂获取回话SqlSession-->相当于Connection
SqlSession session = factory.openSession();
//4.执行指定的SQL语句
Emp emp = session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpByNo",7369);
List<Emp> list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByDeptno",30);
Map<Integer,Emp> map = session.selectMap("com.yjxxt.mappers.EmpMapper.queryEmpByDeptno",20,"empno");
//5.得到结果处理结果
//System.out.println(emp);
//list.forEach(System.out::println);
System.out.println(map);
//6.关闭回话
session.close();
}
}
6.SqlSession封装
/*
对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(); //默认手动 提交事务
//session = factory.openSession(true); //设置自动 提交事务
}
return session;
}
}
7.事务(Transaction)
- 事务是数据库操作的最小单位,有着ACID的特性,应该保证一个事务下的多条SQL语句要么都成功,要么都失败.
- Mybatis中配置了事务管理器,type属性设置JDBC,表示Mybatis采用和原生JDBC相同的事务管理机制
- 在Myabatis执行操作的开始,将自动提交功能关闭了,需要我们在执行DML操作时候,手动提交设置|设置自动提交
手动提交:
session.commit(); //事务提交
设置自动提交事务:
public static SqlSession getSession() {
SqlSession session =null;
if(factory!=null) {
//session = factory.openSession(); //默认手动提交事务
session = factory.openSession(true); //自动提交
}
return session;
}
增删改操作
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="com.yjxxt.mappers.DeptMapper">
<!--查询-->
<select id="queryAll" resultType="Dept">
select * from dept
</select>
<!--insert-->
<insert id="addDept">
insert into dept values(88,'haha','shanghai')
</insert>
<delete id="deleteDept" parameterType="int">
delete from dept where deptno = #{0}
</delete>
</mapper>
Java测试类
/*
测试增删改
事务:
默认手动提交
*/
public class Class001_Test {
public static void main(String[] args) throws IOException {
//获取回话
SqlSession session = SessionUtils.getSession();
//执行sql
//int rows = session.insert("com.yjxxt.mappers.DeptMapper.addDept");
int rows = session.delete("com.yjxxt.mappers.DeptMapper.deleteDept",87);
//得到结果处理结果
if(rows>0){
session.commit();
}else{
session.rollback();
}
//关闭回话
session.close();
}
}
8.入参类型parameterType
基本数据类型|包装类 String Date JAVABEAN 数组 List Map
JAVABEAN : 当sql需要的参数存在多个,并且为一个对象的不同属性,可以先把对个参数封装成javabean对象,然后作为一个入参传递
sql中占位符的名字需要匹配入参对象的属性名
数组|list :sql需要的多个参数是同种类型,一个字段的多个值,适合使用数组|list
sql语句中需要使用foreach标签进行遍历
Map : sql需要的多个参数,不属于一个对象的不不同属性值,可以封装为Map集合中的不同键值对
sql中占位符的名字需要匹配键值对的key
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="com.yjxxt.mappers.EmpMapper">
<!--基本数据类型|包装类: 根据部门编号查询-->
<select id="queryEmpByDeptno" parameterType="int" resultType="Emp">
select * from emp where deptno = #{deptno}
</select>
<!--String: 根据员工姓名查询-->
<select id="queryEmpByName" parameterType="String" resultType="Emp">
select * from emp where ename = #{ename}
</select>
<!--Date: 根据员工入职日期查询-->
<select id="queryEmpByDate" parameterType="date" resultType="Emp">
select * from emp where hiredate = #{hiredate}
</select>
<!--JAVABEAN: 根据员工姓名与部门编号同时查询-->
<select id="queryEmpByNameDeptno" parameterType="emp" resultType="Emp">
select * from emp where ename=#{ename} and deptno = #{deptno}
</select>
<!--数组: 根据多个员工编号查询-->
<select id="queryEmpByidSome" resultType="Emp">
select * from emp where empno in (
<foreach collection="array" item="item" separator=",">
#{item}
</foreach>
)
</select>
<!--Map: 根据员工薪资或者员工所在部门编号查询-->
<select id="queryEmpBySalDeptno" parameterType="map" resultType="Emp">
select * from emp where sal>#{sal} or deptno=#{deptno}
</select>
</mapper>
Java测试类
/*
测试入参类型
*/
public class Class002_Param {
public static void main(String[] args) throws IOException, ParseException {
//获取回话
SqlSession session = SessionUtils.getSession();
//执行sql
List<Emp> list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByDeptno",20);
//list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByName","SMITH");
//Date 1981/12/3
//Date date = new SimpleDateFormat("yyyy/MM/dd").parse("1981/12/3");
//list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByDate",date);
//JAVABEAN
Emp emp = new Emp();
emp.setEname("SMITH");
emp.setDeptno(20);
//Emp emp1 = session.selectOne("com.yjxxt.mappers.EmpMapper.queryEmpByNameDeptno",emp);
//System.out.println(emp1);
//数组|List
//list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpByidSome",new int[]{7369,7499});
//Map
Map map = Map.of("sal",1500,"deptno","10");
list = session.selectList("com.yjxxt.mappers.EmpMapper.queryEmpBySalDeptno",map);
list.forEach(System.out::println);
//关闭回话
session.close();
}
}
9.结果类型 resultType
定义:查询到的结果集中的每一个数据的类型
基本数据类型|包装类 String Date JAVABEAN List Map List<Map>
如果结果类型为List,resultType设置的为集合的泛型类型
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="com.yjxxt.mappers.EmpMapper2">
<!--基本数据类型|包装类 : 根据员工姓名模糊查询员工编号-->
<select id="queryIdByNameLike" parameterType="String" resultType="int">
select empno from emp where ename like '%'||#{ename}||'%'
</select>
<!--Date : 根据员工编号查询员工入职日期-->
<select id="queryDateById" parameterType="int" resultType="Date">
select hiredate from emp where empno = #{empno}
</select>
<!--Map : 根据员工编号查询员工信息 -->
<!--查询到一条数据,返回一个Map,一条数据的不同字段值作为Map集合中的不同键值对-->
<select id="queryMapById" parameterType="int" resultType="Map">
select * from emp where empno = #{empno}
</select>
<!--List<Map> : 根据薪资查询员工信息-->
<select id="queryMapBySal" parameterType="map" resultType="Map">
select empno,ename,sal,comm,deptno from emp where sal between #{low} and #{high}
</select>
</mapper>
Java测试类
/*
测试结果类型
*/
public class Class003_Result {
public static void main(String[] args) throws IOException, ParseException {
//获取回话
SqlSession session = SessionUtils.getSession();
//执行sql
//int
/*List<Integer> list1 = session.selectList("com.yjxxt.mappers.EmpMapper2.queryIdByNameLike","A");
list1.forEach(System.out::println);*/
//Date
/*Date date = session.selectOne("com.yjxxt.mappers.EmpMapper2.queryDateById",7369);
System.out.println(date);*/
//Map
//Map<String,Object> map = session.selectOne("com.yjxxt.mappers.EmpMapper2.queryMapById",7369);
List<Map<String,Object>> list = session.selectList("com.yjxxt.mappers.EmpMapper2.queryMapBySal",Map.of("low",1000,"high",1500));
list.forEach(System.out::println);
//关闭回话
session.close();
}
}
10.接口绑定方案
映射文件:
- 接口名与SQL映射文件名字保持一致,同时放在同一个包下
- SQL映射文件命名空间要求定义为: 与之绑定的接口的包名.文件名
- sql标签的id属性值要求与所对应的抽象方法的方法名保持一致
- SQL的参数与返回值要求与对应的抽象方法的参数与返回值保持一致
在核心配置文件中扫描接口
<!--扫描接口绑定方案-->
<mappers>
<!--扫描一个指定的接口-->
<!--<mapper class="com.yjxxt.mappers.DeptMapper"/>-->
<!--扫描一个包下的所有接口-->
<package name="com.yjxxt.mappers"/>
</mappers>
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="com.yjxxt.mappers.DeptMapper">
<select id="queryAll" resultType="dept">
select * from dept
</select>
<!--如果参数只有一个,站位符的名字可以任意定义-->
<select id="queryDeptByNo" parameterType="int" resultType="dept">
select * from dept where deptno = #{id}
</select>
<!--多参数 : sql语句中占位符的名字默认为[arg1, arg0, param1, param2]-->
<select id="queryDeptByNameDeptno" resultType="dept">
<!--select * from dept where dname = #{param1} and loc = #{param2}-->
select * from dept where dname = #{dname} and loc = #{loc}
</select>
<!--入参javabean,占位符的名字匹配对象的属性名-->
<insert id="insertDept" parameterType="dept">
insert into dept values(#{deptno},#{dname},#{loc})
</insert>
<!--update-->
<update id="updateDept">
update dept set dname=#{dname} where deptno = #{deptno}
</update>
</mapper>
定义接口
/*
测试接口绑定方案
接口名与SQL映射文件名字保持一致
同时放在同一个包下
*/
public interface DeptMapper {
//查询所有的部门信息
List<Dept> queryAll();
//根据部门编号查询部门信息
Dept queryDeptByNo(int deptno);
//根据部门姓名与部门位置一起查询
//@Param("参数别名") sql语句中占位符的名字可以对应通过@Param注解定义的别名
Dept queryDeptByNameDeptno(@Param("dname") String dname,@Param("loc") String loc);
//insert
int insertDept(Dept dept);
//修改update 根据部门编号修改部门名称
int updateDept(@Param("deptno") int deptno,@Param("dname") String dname);
}
Java测试类
/*
测试接口绑定方案
*/
public class Class001_Test {
public static void main(String[] args) throws IOException {
//获取回话
SqlSession session = SessionUtils.getSession();
//获取接口的实现类对象
DeptMapper mapper = session.getMapper(DeptMapper.class);
//通过实现类对象调用重写后的方法
List<Dept> list = mapper.queryAll();
//list.forEach(System.out::println);
Dept dept = mapper.queryDeptByNo(20);
dept = mapper.queryDeptByNameDeptno("SALES","shanghai");
System.out.println(dept);
//insert
//mapper.insertDept(new Dept(91,"渠道部","学校"));
//update
mapper.updateDept(90,"网络部");
//关闭回话
session.close();
}
}
多参数传递
1 方式一
a)接口中定义方法
User selByUP(String username, String password);
b) 映射文件中提供对应的标签. 此时, SQL 语句中获取方式有两种, 通过#{arg+数字}或#{param+数字}的方式.
<select id="selByUP" resultType="user">
select * from t_user where username=#{param1} and password=#{param2}
</select>
2 方式二
a) 接口中定义方法, 参数中使用@Param 注解设定参数名用于在 SQL 语句中使用.
User selByUP(@Param("username") String username, @Param("password")
String password);
b) 映射文件中提供对应的标签. 此时, SQL 语句中获取方式有两种, 通过#{参数名称}或#{param+数字}的方式.
<select id="selByUP" resultType="user">
select * from t_user where username=#{username} and
password=#{password}
</select>