MyBatis 灵活的ORM框架
理解ORM的概念
掌握MyBatis框架的构建
了解MyBatis的相关配置
掌握多表映射技术
掌握动态SQL语句处理
什么是MyBatis?
(了解)MyBatis的前身是iBatis,是Apache基金会的开源的项目,该框架可以自定义SQL语句与实体映射关系,屏除了大部分JDBC代码、手动设置参数和结果集的重获,通过简单的XML或注解来配置和映射基本数据类型、Map接口和POJO到数据库记录。该项目于2010年5月代码库迁至GooleCode,后更名为MyBatis。
ORM
对象关系映射,全称是Object Relational Mapping,是一种为了解解决面向对象与关系数据库存在的互不匹配的现象的技术。
ORm通过使用描述对象和数据库之间映射的元数据,将Java程序中的对象自动持久化到数据库中。本质上就是将数据从一种形式转化到另一种形式。
ORM可以方便地将Java中的对象与数据库中的表进行统一化操作。
框架构建
构建MyBatis框架的步骤
1、导入MyBatis所需的Jar包
2、classPath中添加MyBatis配置文件
3、创建数据表的映射类
4、创建映射类的Dao接口
5、编写映射类的Dao映射文件
1、导入MyBatis所需的jar包
2、添加配置文件 在classpath中添加 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>
<!-- 设置对象的别名 -->
<typeAliases>
<typeAlias type="com.niit.bean.Employee" alias="emp"/>
</typeAliases>
<environments default="niit">
<environment id="niit">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@192.168.9.11:1521:niit"/>
<property name="username" value="system"/>
<property name="password" value="niit"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/niit/mapper/empMapper.xml"/>
</mappers>
</configuration>
enviroments表示配置框架的基本环境
default表示默认的配置
enviroment的id应和default一致
transactionManger表示设置事务处理方式 type值分为JDBC和MANAGED
JDBC表示使用JDBC的提交回滚功能
MANAGED表示什么也不做,不提交,回滚,关闭连接
dataSource表示设置数据源 type值有UNPOOLED,POOLED,JNDI
UNPOOLED表示非数据池连接,每次请求都将开启一个新的数据库连接
POOLED表示数据池连接方式,缓存数据库连接对象
JNDI表示与服务器配套的远程连接数据源
Property的name值都是固定写法
使用typeAliases简化实体类的使用
简化后的实体类可以通过别名直接在映射文件mapper中使用,如parameterType、resultType属性
3、创建数据表的映射类
table user对应的User类
4、创建映射类的dao接口
如:EmpDao.java
public interface EmpDao {
/**
* 查询所有员工信息
* @return
*/
public List<Employee> findAllEmps();
}
5、编写dao的映射文件 XXXMapper.xml 该映射文件配置用于建立实体类和数据表的联系
如EmpDao.java编写一个empMapper文件,在MyBatis配置文件通过mapper建立映射关系(resource设置完整的路径)
<mappers>
<mapper resource="com/niit/mapper/empMapper.xml"/>
</mappers>
empMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
<!-- 用来映射DAO接口与实体Bean -->
<!-- 根据DAO接口中定义的数据访问方法生成DAO的实现类并进行ORM操作 -->
<mapper namespace="com.niit.dao.EmpDao">
<!-- 映射查询方法 ,id表示接口中的方法名, resultType表示数据查询后映射在JavaBean中的类型-->
<select id="findAllEmps" resultType="com.niit.bean.Employee">
select employee_id ,first_name as firstName,last_name as lastName,salary,hire_date as hireDate from emp
</select>
</mapper>
MyBatis有着非常灵活的操作方式,SQL语句由开发人员自己控制。
实体映射文件配置说明
select 映射查询语句
insert 映射新增语句
update 映射修改语句
delete 映射删除语句
(1)namespace属性设置对应的dao接口 (一个dao接口对应一个mapper文件)
(2)所有增删改查操作必须设置id属性,表示dao中对应的方法
(3)方法参数使用parameterType和parameterMap(后面会详细讲解)
(4)查询的返回值使用resultType或者resultMap(多表映射会详细讲解)
<!-- 映射查询方法 ,id表示接口中的方法名, resultType表示数据查询后映射在JavaBean中的类型-->
<select id="findAllEmps" resultType="com.niit.bean.Employee">
select employee_id ,first_name as firstName,last_name as lastName,salary,hire_date as hireDate from emp
</select>
<update id="modifyEmp" parameterType="com.niit.bean.Employee">
update emp set salary=#{salary}, hire_date=#{hireDate} where employee_id=#{empId}
</update>
参数值:
parameterType应用:表示参数的类型
默认类型为map,表示参数为map集合,parameterType写入的参数,在SQL语句中可以通过#{属性}或#{键名}的方式访问对象的数据或map集合的数据
1、如果值为基本数据类型 ,如int 则可以使用#{任意值}访问
2、如果值为对象,如Employee类则可以使用#{属性名}访问
parameterMap很少使用,不做介绍
关于多个参数传入的方式:
(1)根据索引访问传入的数据
public List<Employee> findEmpsByDateAndSalary(Date date, double salary);
<select id="findEmpsByDateAndSalary" resultType="emp">
select employee_id ,first_name as firstName,last_name as lastName,salary,hire_date as hireDate from emp
where hire_date<#{0} and salary>#{1}
</select>
(2)使用Map传入多个参数,根据#{键名}访问传入的数据
public List<Employee> findEmpsByDateAndSalary(Map<String, Object> map);
<select id="findEmpsByDateAndSalary" parameterType="map" resultType="emp">
select employee_id ,first_name as firstName,last_name as lastName,salary,hire_date as hireDate from emp
where hire_date<#{date} and salary>#{money}
</select>
(3)使用JavaBean传入多个参数,将多个参数封装成Java对象,根据#{属性名}访问传入的数据
跟传入对象参数一致
(4)使用@param注解访问多个参数
public List<Employee> findEmpsByDateAndSalary(@Param("hireDate")Date date, @Param("money") double salary);
<select id="findEmpsByDateAndSalary" resultType="emp">
select employee_id ,first_name as firstName,last_name as lastName,salary,hire_date as hireDate from emp
where hire_date<#{hireDate} and salary>#{money}
</select>
返回值
resultType的使用:设置返回值的类型,对于返回类型为集合,只需要泛型的类型即可。
如上的多个参数的例子中返回为List集合,但只需要设置resultType=com.niit.bean.Employee
*resultMap的使用
<resultMap type="emp" id="empMap">
<id property="empId" column="employee_id"/>
<result property="empName" column="employee_name"/>
</resultMap>
resultMap的type属性表示设置实体对象,
id表示设置resultMap的别名
id表示主键字段,result表示普通字段
property表示实体对象中用于映射column的属性名(即实体bean的属性名)
column表示数据表的字段名
定义好的resultMap可以直接通过id值来使用
<select id="findEmpsByDateAndSalary" resultMap="empMap">
select employee_id ,empName from emp
where hire_date<#{0} and salary>#{1}
</select>
执行数据操作时,如果实体对象的属性名和数据表的字段名不匹配,会出现sql异常,并提示标识符无效
使用MyBatis框架实现数据访问
(1)读取配置文件
(2)创建SessionFactoryBuilder
(3)创建SessionFactory
(4)打开Session
(5)获取dao实例
//读取资源文件
Reader reader = Resources.getResourceAsReader("config.xml");
//创建sqlSessionFactoryBuilder
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//使用构建器根据资源文件创建会话工厂
SqlSessionFactory factory = builder.build(reader);
//使用会话工厂打开会话,会话表示应用服务器与数据库的通信,封装了JDBC的API对象
SqlSession session = factory.openSession();
//根据映射文件获取DAO的实现类
EmpDao empDao = session.getMapper(EmpDao.class);
(6)执行查询操作或增删改操作
List<Employee> list = empDao.findEmpsByDateAndSalary(new SimpleDateFormat("yyyy-MM-dd").parse("2005-1-1"), 6000);
for(Employee emp : list){
System.out.println(emp.getEmpId()+"\t"+emp.getFirstName()+"\t"+emp.getSalary()+"\t"+new SimpleDateFormat("yyyy-MM-dd").format(emp.getHireDate()));
}
(7)提交关闭session
对于增删改的操作需要提交事务
//提交事务(查询操作不需要提交事务)
session.commit();
//关闭会话(断开数据库连接,释放占用资源)
session.close();
序列自动增长(只做了解,因为数据库增加记录的操作都需要自己提供如Oracle的XXX.nextVal)
在执行insert操作时
<insert id="" parameterType="" >
//先查询自增主键值
<selectKey order="BEFORE" keyProperty="empId" resultType="int" >
select empId.nextVal from dual
</selectKey>
insert into emp values(#{empId},......)0
</insert>
selectKey中的keyProperty属性表示产生后的序列。
执行insert操作时,先查询自增主键值,在insert的SQL语句中用#{keyProperty}访问序列值。
(该操作还不如在SQL直接使用nextVal插入序列值)
多表映射
ORM框架的核心就是多表映射,MyBatis的多表映射主要分为
一对多映射
多对一映射
(在Hibernate中还有个多对多映射)
多表映射能以面向对象的方式基于一个对象来获取多表的关联数据。
多对一映射
多对一映射主要用于字表映射。根据外检查询主表映射的对象。
如下映射的实体类
public class Employee {
private int empId;
private String firstName;
private String lastName;
private double salary;
private Date hireDate;
//多对一的关联映射(将表中的外键映射为对象)
private Department dep;
。。。。。。
}
public class Department {
private int depId;
private String depName;
。。。。。。
}
多对一映射在实体映射文件中配置
<!-- 多对一关联查询 -->
<!-- 配置resultMap是为了解决结果集中与映射Bean数据不一致的情况 -->
<!-- resultMap配置时,如果没有进行多表映射,那么和数据表同名的属性可以不写,但是一旦进行了表关联映射则必须将每一个属性都和数据表字段一一映射 -->
<resultMap type="com.niit.bean.Employee" id="empMap">
<id property="empId" column="employee_id"/>
<result property="firstName" column="first_name"/>
<result property="lastName" column="last_name"/>
<result property="hireDate" column="hire_date"/>
<result property="salary" column="salary"/>
<!-- 配置多对一映射 -->
<association property="dep" javaType="dep">
<id property="depId" column="department_id"/>
<result property="depName" column="department_name"/>
</association>
</resultMap>
association表示外键映射的实体bean,需要配置该实体类与数据表的相关映射
property表示外键映射的对象在当前类的的属性名;
javaType表示该对象对应的类型
映射SQL语句需要以外键作为关联条件,将外键映射对象的数据一并查询出来。
<select id="findEmpAndDepById" parameterType="int" resultMap="empMap">
select employee_id ,first_name,last_name ,salary,hire_date,emp.department_id,department_name from emp,dep
where employee_id=#{empId} and emp.department_Id=dep.department_id
</select>
效率高的可以使用相关子查询,注意查询的列需要和property值一致 如:(select department_name from dep where
emp.department_Id=dep.department_id
) as depName 需要取别名。
一对多映射
映射的实体bean
public class Department {
private int depId;
private String depName;
//一对多映射
private List<Employee> empList;
。。。。。。。
}
public class Employee {
private int empId;
private String firstName;
private String lastName;
private double salary;
private Date hireDate;
。。。。。。
}
一对多映射在映射文件中配置
<mapper namespace="com.niit.dao.DepDao">
<!-- 配置一对多映射 -->
<resultMap type="dep" id="depMap">
<id property="depId" column="department_id"/>
<result property="depName" column="department_name"/>
<!-- 配置一对多集合 -->
<collection property="empList" ofType="emp">
<id property="empId" column="employee_id"/>
<result property="firstName" column="first_name"/>
<result property="lastName" column="last_name"/>
<result property="salary" column="salary"/>
<result property="hireDate" column="hire_date"/>
<!-- 嵌套多对一的映射 -->
<association property="dep" javaType="dep">
<id property="depId" column="department_id"/>
<result property="depName" column="department_name"/>
</association>
</collection>
</resultMap>
<select id="findDepById" parameterType="int" resultMap="depMap">
select dep.department_id,department_name,employee_id,first_name,last_name,hire_date,salary
from emp,dep where emp.department_id=dep.department_id and dep.department_id=#{id}
</select>
</mapper>
collection表示一对多的集合,ofType表示集合的对象的类型
动态SQL
动态SQL语句是MyBatis的强大特性,用于灵活的进行SQL语句的拼接。
主要有
if
choose(when,otherwise)
foreach
(1)if语句主要用于多条件的拼接
当业务逻辑中有多个条件筛选,则SQL语句中可能只有一个条件,也可能会有多个条件,if语句可以进行很好的拼接。
例如:选择商品根据多个条件进行查询时
public List<Employee> findEmpBySalary(@Param("min") double minSalary, @Param("max") double maxSalary);
<!-- if动态SQL语句的实现 -->
<select id="findEmpBySalary" resultMap="empMap">
select employee_id,first_name,last_name,salary,hire_date from emp where 1=1
<if test="min!=0">
and salary>=#{min}
</if>
<if test="max!=0">
and salary<=#{max}
</if>
</select>
注意点:在映射文件里<用<表示;
int类型和0比较,引用类型和null比较;
(2)choose语句用于多条件的拼接
当从多个条件选项中选择一个匹配的,可以通过choose语句实现。
public List<Employee> findEmpByEmpIdOrDepName(@Param("empId") int empId,@Param("depName") String depName);
<select id="findEmpByEmpIdOrDepName" resultMap="empMap">
select employee_id,first_name,last_name,salary,hire_date from emp,dep where emp.department_id=dep.department_id
<choose>
<when test="empId!=-1 and depName==null">
and employee_id=#{empId}
</when>
<when test="empId==-1 and depName!=null">
and department_name=#{depName}
</when>
<otherwise>
and salary>=10000
</otherwise>
</choose>
</select>
(3)foreach语句用于对值的遍历
主要用在in条件的SQL语句中
public boolean deleteEmpById(List<Integer> idList);
<!-- foreach的collection属性表示要删除集合,默认值有list以及array,自定义的值表示参数中的集合或数组属性 -->
<delete id="deleteEmpById">
delete from emp where employee_id where in
<foreach collection="list" item="empId" open="(" close=")" separator=",">
#{empId}
</foreach>
</delete>
collection表示集合对象,默认值为list和collection,此时方法参数为集合对象;当参数类型为对象时,collection应写入对象中集合类型的属性名。
item表示遍历的元素别名
open表示foreach开始的内容
close表示foreach结束的内容
separator表示多个元素分隔的内容
foreach使用#{item}的方式获取遍历的元素值