MyBatis简介
原是Apache的一个开源项目iBatis, 2010年6月这 个项目由Apache Software Foundation 迁移到了 Google Code,随着开发团队转投Google Code 旗下, iBatis3.x正式更名为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对象)映射成数据库中的记录
MyBatis优点
• MyBatis是一个半自动化的持久化层框架。
• JDBC
– SQL夹在Java代码块里,耦合度高导致硬编码内伤 – 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见
• Hibernate和JPA – 长难复杂SQL,对于Hibernate而言处理也不容易 – 内部自动生产的SQL,不容易做特殊优化。
– 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。 导致数据库性能下降。
• 对开发人员而言,核心sql还是需要自己优化
• sql和java编码分开,功能边界清晰,一个专注业务、 一个专注数据
MyBatis操作数据库的两种方式
一、SqlSession操作数据库
//1、根据全局配置文件,利用 SqlSessionFactoryBuilder创建SqlSessionFactor
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2、使用SqlSessionFactory获取sqlSession对象。一个 SqlSession对象代表和数据库的一次会话
SqlSession openSession = sqlSessionFactory.openSession()
//3、使用SqlSession根据方法id进行操作
try {
Employee employee = openSession.selectOne("com.atguigu.mybatis.EmployeeDaoImpl.getEmpById", 1);
System.out.println(employee);
} finally {
openSession.close();
}
二、接口式编程
// 1、获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);;
// 2、获取sqlSession对象
SqlSession openSession = sqlSessionFactory.openSession();
try {
// 3、获取接口的实现类对象
//会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpById(1);
System.out.println(mapper.getClass());
System.out.println(employee);
} finally {
openSession.close();
}
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
}
MyBatis全局配置文件
mybatis-config.xml
Setting
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行
typeAliases别名处理器
值得注意的是,MyBatis已经为许多常见的 Java 类型内建 了相应的类型别名。它们都是大小写不敏感的,我们在起 别名的时候千万不要占用已有的别名
别名 | 映射的类型 |
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
string | String |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
Mapper.xml映射文件
插入时的主键生成策略
insert into tbl_employee(last_name,email,gender)
values(#{lastName},#{email},#{gender})
select EMPLOYEES_SEQ.nextval from dual
insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL)
values(#{id},#{lastName},#{email})
MyBatis参数处理
单个参数:mybatis不会做特殊处理,
#{参数名/任意名}:取出参数值。
多个参数:mybatis会做特殊处理。
多个参数会被封装成 一个map,
key:param1.param2...paramN,或者参数的索引也可以
value:传入的参数值
#{}就是从map中获取指定的key的值;
操作:
方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
取值:#{id},#{lastName}
异常:
org.apache.ibatis.binding.BindingException:
Parameter 'id' not found.
Available parameters are [1, 0, param1, param2]
解决异常:【命名参数】:明确指定封装参数时map的key;@Param("id")
多个参数会被封装成 一个map,
key:使用@Param注解指定的值
value:参数值
#{指定的key}取出对应的参数值
POJO:
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;
#{属性名}:取出传入的pojo的属性值
Map:
如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map
#{key}:取出map中对应的值
TO:
如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象
Page{
int index;
int size;
}
========================思考================================
public Employee getEmp(@Param("id")Integer id,String lastName);
取值:id==>#{id/param1} lastName==>#{param2}
public Employee getEmp(Integer id,@Param("e")Employee emp);
取值:id==>#{param1} lastName===>#{param2.lastName/e.lastName}
##特别注意:如果是Collection(List、Set)类型或者是数组,
也会特殊处理。也是把传入的list或者数组封装在map中。
key:Collection(collection),如果是List还可以使用这个key(list)
数组(array)
public Employee getEmpById(List ids);
取值:取出第一个id的值: #{list[0]}
========================结合源码,mybatis怎么处理参数==========================
总结:参数多时会封装map,为了不混乱,我们可以使用@Param来指定封装时使用的key;
#{key}就可以取出map中的值;
(@Param("id")Integer id,@Param("lastName")String lastName);
ParamNameResolver解析参数封装map的;
===========================参数值的获取======================================
#{}:可以获取map中的值或者pojo对象属性的值;
${}:可以获取map中的值或者pojo对象属性的值;
select * from tbl_employee where id=${id} and last_name=#{lastName}
Preparing: select * from tbl_employee where id=2 and last_name=?
区别:
#{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
${}:取出的值直接拼装在sql语句中;会有安全问题;
大多情况下,我们取参数的值都应该去使用#{};
原生jdbc不支持占位符的地方我们就可以使用${}进行取值
比如分表、排序。。。;按照年份分表拆分
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}
#{}:更丰富的用法:
规定参数的一些规则:
javaType、 jdbcType、 mode(存储过程)、 numericScale、
resultMap、 typeHandler、 jdbcTypeName、 expression(未来准备支持的功能);
jdbcType通常需要在某种特定的条件下被设置:
在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错);
JdbcType OTHER:无效的类型;因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,oracle不能正确处理;
由于全局配置中:jdbcTypeForNull=OTHER;oracle不支持;
有两种办法
1、#{email,jdbcType=NULL};
2、jdbcTypeForNull=NULL 在mybatis全局配置中配置setting