Mybatis入门基础
mybatis是apache下的持久层的一种框架。开发dao有两种方法。
- 原始dao开发方法
- mybatis的mapper代理开发方法
传统jdbc的缺点
- 访问数据库时建立连接,不使用立即释放,频繁开启和关闭连接,造成资源浪费,影响性能。
- 建立连接耗费时间大量时间
解决方案:使用数据库连接池管理 - sql语句硬编码,不利于系统维护
- 设置参数位置和参数内容硬编码
- 查询结果硬编码
解决方案:将sql语句配置在xml中,输入参数和输出参数映射在java对象上
mybatis的关键
- 配置文件
SqlMapConfig.xml (Mybatis全局配置文件,名称不固定)
配置数据库,事务等mybatis运行环境 - mybatis核心
输入输出参数和动态sql
通过mapper.xml映射文件
工作原理
一、创建SqlSessionFactory(会话工厂)
作用:创建SqlSession
二、SqlSession对象(会话、接口)
作用:操作数据库(发出sql)
三、Executor(执行器、接口,有两个方法(基本执行器和缓存执行器))
作用:操作者,SqlSession通过执行Executor操作数据库
四、mapped statement(底层封装对象)
作用:对操作数据库存储封装,包括sql语句、输入参数和输出参数(用pojo封装或map)。
运行环境
jar包下载https://github.com/mybatis/mybatis-3/releases
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- 测试jar包 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
log4j.properties
# Global logging configuration
#在开发环境下日志级别设置成DEBUG,生产环境设置info或error
log4j.rootLogger=DEBUG, stdout
# Global output
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
SqlMapConfig.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>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- jdbc事务管理 -->
<transactionManager type="JDBC"/>
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/statement?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="yali"/>
</dataSource>
</environment>
</environments>
</configuration>
在src/main/resources下添加mapper文件夹,存放mapper.xml映射文件
测试mybatis
UserMapper.xml
在mappers下建立UserMapper.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" >
<!-- 命名空间,对sql分类化管理 使用代理模式时要对应mapper.java类 -->
<mapper namespace="test">
<!-- 在映射文件中配置sql语句 -->
<!-- 通过select执行数据库查询语句,id标识映射文件中的sql mybatis会将sql封装到mappedStatement对象中 -->
<!-- 需求:通过id查询user对象 使用#{}标识占位符 里面的内容表示输入的参数名(简单类型可以直接写value 不建议)
parameterType:输入参数类型 简单类型可以不写
resultType:输出参数类型 将记录映射成java对象-->
<select id="findUserById">
select * from user where id=#{id}
</select>
</mapper>
SqlMapConfig.xml中配置加载文件
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- jdbc事务管理 -->
<transactionManager type="JDBC"/>
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/statement?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="yali"/>
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="mappers/UserMapper.xml"/>
</mappers>
java pojo对象
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String mobileNumber;
private String loginPwd;
private String email;
private String nickname;
private Date ctime;
private Date mtime;
//对应的get set方法
}
用户查询测试
public class MybatisFirst {
//根据id查询用户信息,一条结果
@Test
public void findUserById() throws IOException {
//通过配置文件得到流对象
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//创建SqlSession
SqlSession session = factory.openSession();
//通过SqlSession执行sql 第一个参数是映射文件UserMapper.xml的方法id 第二个参数是输入参数类型
User user = session.selectOne("test.findUserById",1);
System.out.println(user);
session.close();
}
}
可以看出mobileNumber和loginPwd没有值(数据库和java类型不匹配,后面可以采用别名或resultMap来赋值)
- 别名
2.resultMap
多条用户查询
返回结果依旧用pojo对象接收
模糊查询
用户一般会忘记传入%,在sql中可以写select * from user where nickname like ‘%${value}%’
简单类型
内
部
必
须
写
v
a
l
u
e
,
{}内部必须写value,
内部必须写value,{}会引起sql注入,不建议
- 返回多个结果只能用selectList,不能用selectOne
- 返回1个结果可以用selectOne,也能用selectList
添加用户
id为自增的,UserMapper.xml写insert也可以不写id字段
主键返回
insert语句生成的自增主键,很多时候需要获取,作为子表的一个字段,有三种方法获取
- 存储过程中常用select last_insert_id()函数
- 常用
- 使用UUID(适用于主键非自增)
删除用户
修改用户
mybatis开发dao
SqlSession使用范围
- 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory,SqlSessionFactory可以采用单例模式,一旦创建只有一个实例。与spring整合后,使用单例模式管理,SqlSessionFactoryBuilder生成工具类。
- 通过SqlSessionFactory创建SqlSession,SqlSession是面向用户(程序员)的接口,含有多种操作数据库的方法和数据域属性,线程不安全。SqlSession最佳应用场合在方法体内,定义局部变量使用。
原始dao开发(dao接口和dao实现类)
思路:通过注入SqlSessionFactory对象,在方法中生成SqlSesison会员,执行方法
建立测试案例
mapper代理方法(只需要mapper接口)
原始dao开发的问题:
- dao的接口实现类方法中存在大量的模板方法,设想将这些代码提取出来
- 调用sqlSession方法,将statement的id硬编码(test.findUserById)
- 调用sqlSession方法传入的变量,犹豫sqlSession方法使用泛型,即使传入变量类型错误,编译阶段也不报错。
mapper代理方法思路:
编写mapper接口和mapper.xml映射文件
mapper.xml需要遵循一些规范,mybatis可以自动生成mapper接口实现类代理对象
- 在mapper.xml中 namespace等于mapper接口的地址(com.shyb.mapper.UserMapper)
- mapper.java接口中的方法名和mapper.xml中statement的id一致
- mapper.java接口中的方法输入参数类型和mapper.xml中的paramterType指定类型一致。
- mapper.java接口中的方法返回值类型和mapper.xml中的resultType指定类型一致
问题:
mapper的参数映射只有1个paramterType,要传递多参数时怎么传递?
可以使用pojo或map,简单类型可以不写,mapper写多参数时需要@Param注解
SqlMapConfig.xml详解
- properties(属性)
- settings(全局配置参数)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境集合属性对象)
- environment(子属性对象)
- transactionManager(事务管理)
- datasource(数据源)
- mappers(映射器)
- environment(子属性对象)
properties(属性)
将属性配置在db.properties中,在SqlMapConfig.xml中加载db.properties,在SqlMapConfig.xml中就不需要对数据库连接配置硬编码。
<!-- 加载属性文件 -->
<properties resource="db.properties"></properties>
<dataSource type="POOLED">
<property name="driver" value="${db_driver}"/>
<property name="url" value="${db_url}"/>
<property name="username" value="${db_username}"/>
<property name="password" value="${db_password}"/>
</dataSource>
settings(全局配置参数)
mybatis调整一些运行参数,如开启二级缓存,开始延迟加载
typeAliases(类型别名)
不常用。在mapper.xml中paramterType和resultType中pojo全名很长,可以定义别名。方便开发。
<typeAliases>
<!-- 针对单个 -->
<typeAlias type="com.shyb.bean.User" alias="User"/>
</typeAliases>
<typeAliases>
<!-- 批量指定别名 别名就是类名 -->
<package name="com.shyb.bean" />
</typeAliases>
typeHandlers(类型处理器)
mybatis通过typeHandlers完成jdbc和java类型转化,一般提供的就够用
mappers(映射器)
<mappers>
<!-- 通过resource去加载一个映射文件 -->
<mapper resource="mappers/UserMapper.xml"/>
<!--批量加载 -->
<<package name="com.shyb.mapper"/>"/>
</mappers>
输入映射
传递包装类型的pojo对象
如查询条件很复杂(包含订单信息)
扩展的方式:
- 在原有属性上扩展(如:用户信息 表中不存在,逆向工程生成的),不建议修改原有pojo对象,可以生成一个UserCustom类继承User类,添加额外属性
- 建立Vo类,User作为属性,再添加其他属性
输出映射
- resultType
使用resultType作为映射,只有查询出来的列名与pojo属性名一致,才能映射成功。- 输出类型为单行单列可以直接用简单类型
- 输出类型为单行或多行pojo对象,resultType一样,区别是java中返回是pojo对象还是List.
- 输出结果也可以用hashMap接收(如下 key是count(1) value是9)
- resultMap
如果查询的列名和pojo的属性名不一致,可以定义一个resultMap来接收
动态sql
mybatis核心 对sql语句进行灵活操作,通过对表达式判断,对sql进行灵活拼接
sql片段
动态sql所有查询都采用会有大量重复代码,可以定义sql片段,重复利用,sql片段基于表名,可重复率高,不要包含where标签
foreach标签
想sql传递数组或集合
UserQueryVo对象添加ids属性
private List<Integer> ids;