MyBatis环境搭建:
1、新建Java项目
2、导入jar包(. mybatis核心jar包、 mybatis依赖jar、包数据库驱动jar包、 Add as Library)
3、Mybatis配置文件
<!-- 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映射文件-->
<?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: 命名空间
注意:不要忘记mybatis核心xml文件中的mapper配置
4.4. 测试
5. Mybatis配置文件详解
5.1. 核心配置文件
1.configuration
配置文件的根元素,所有其他的元素都要在这个标签下使用(dtd文件规定)
2.environments default="environment"
用于管理所有环境, 并可以指定默认使用那个环境,通过defualt属性来指定
3.environment
用来配置环境,id属性用于唯一标识当前环境
4.transactionManager type="JDBC"
用户配置事务管理器
-->
<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 SQL映射文件:
在Mybatis中,推荐使用mappers作为包名,我们只需要写一个映射配置文件就可以,UserMapper.xml,用于
定义要执行的sql语句,同时可以设置参数|返回值结果类型
4、测试
SQL映射文件(mapper)
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
1.mapper
SQL映射文件的根元素
namespace 属性
用于指定命名空间, mydatis通过namespace+id的方式用来定位sql语句,所以必须要指定
namespace,通过被配置为权限定路径 包名+xml文件名(不带后缀名
三个查询方法
selectList("命名空间.id") 用户查询多条数据情况,返回一个List集合, 没有查到数据返回空集合,不是
null
selectOne("命名空间.id") 用于查询单条数据,返回一个数据, 如果没有查到返回null
selectMap("命名空间.id",key的字段名) 用于查询多条记录情况, 返回Map集合, 需要指定那个属性
作为key, sql查询结果作为value,指定的字段值作为key, 如果查不到, 返回一个空map集合,不是null
标签
properties
:实现软编码
src下定义配置文件db.properties
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=SCOTT
password=TIGER
9. typeAliases标签
用于给java类型定义别名,方便在配置文件中使用
9.1.2. 省略alias属性, 表示类别名为类名, 大小写不敏感
<typeAliases>
<typeAlias type="com.yjxxt.pojo.User"/>
alias属性不写,默认类名,不区分大小写
</typeAliases>
9.1.3. 可以通过package标签给整个包下的所有类定义别名,别名为类名
<typeAliases\>
\<package name=\"com.yjxxt.pojo\"/\> \<!\-- 包下所有的类默认类名 \--\>
\</typeAliases\>
\<select id=\"queryAll\" resultType=\"u\"\>
> select id,uname,upwd,birthday from t_user
\</select\>
\<select id=\"queryById\" resultType=\"User\"\>
> select id,uname,upwd,birthday from t_user where id=125
\</select\>
10. parameterType入参类型
如果执行的是条件查询,DML,需要在调用方法的时候传递参数,此时,
可以在sql标签中通过
parameterType属性指定参数的类型(别名|权限定名).
而在sql语句,通过#{}的方式获取参数
10.1. 一个参数的查询
例如: 根据id查询用户信息,当参数只有一个,#{}可以任意填写匹配参数
<!-- 根据用户id查询用户信息 -->
<select id="queryById" resultType="string" parameterType="int">
select uname from t_user where id=#{id} <!-- 可以任意填写 -->
</select>
SqlSession session = null;
try {
//获取会话工厂
SqlSessionFactory factory = new
SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-
config.xml"));
//通过工厂生产会话session对象
session = factory.openSession();
//根据id查询用户名 第二个参数为sql传递的参数
String
name=session.selectOne("com.yjxxt.mapper.UserMapper.queryById", 126);
System.out.println(name);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
session.close();
}
10.2. 多个参数查询
多个参数传递时, 由于sqlSession中提供的查询方法,只允许传递一个sql参数,
因此可以对多个参数进行
封装,可以对象,集合,数组..
<!-- 入参类型: Javabean -->
<select id="queryUserByNamePwd" parameterType="user"
resultType="User">
<!-- 如果参数为对象,可以通过#{对象的属性名}匹配不同的属性值 -->
select <include refid="user_all_field"/> from t_user where uname
=#
{uname} and upwd = #{upwd}
</select>
/*
* 参数为Javabean User对象
* 根据用户名和密码查询用户信息
*/
User user = new User("zhaoliu","4567");
List
list=session.selectList("com.yjxxt.mapper.UserMapper.queryUserByNamePwd",
user);
System.out.println(list);
10.3. 入参类型
parameterType: 基本数据类型(四类八种) 包装类 String Date Javabean Map
List 数组 ...
10.3.1. 基本数据类型|包装类
<!-- 入参类型: 基本数据类型int|Integer -->
<!-- 根据用户id查询用户信息 -->
<select id="queryById" resultType="string" parameterType="int">
</select>
/* 参数基本数据类型 int->Integer
* 根据id查询用户名 第二个参数为sql传递的参数
*/
String name=session.selectOne("com.yjxxt.mapper.UserMapper.queryById",
126);
System.out.println(name);
10.3.2. String
<!-- 入参类型 : String 根据用户名查询用户信息-->
<select id="queryUserByName" parameterType="String"
resultType="User">
select <include refid="user_all_field"/> from t_user where uname =
#{0}
</select>
//测试参数类型: String
List<User>
list=session.selectList("com.yjxxt.mapper.UserMapper.queryUserByName",
"zhangsan");
list.forEach(System.out::println);
10.3.3. JavaBean
<!-- 入参类型: Javabean -->
<select id="queryUserByNamePwd" parameterType="user"
resultType="User">
<!-- 如果参数为对象,可以通过#{对象的属性名}匹配不同的属性值 -->
select <include refid="user_all_field"/> from t_user where uname
=#{uname}
and upwd = #{upwd}
</select>
/*
* 参数为Javabean User对象
* 根据用户名和密码查询用户信息
*/
User user = new User("zhaoliu","4567");
List
list=session.selectList("com.yjxxt.mapper.UserMapper.queryUserByNamePwd",
user);
System.out.println(list);
10.3.4. Map
<!-- 入参类型: Map 根据多个id,查询用户信息-->
<select id="queryUserByIdMap" parameterType="map"
resultType="user">
select <include refid="user_all_field"/> from t_user where id =
#{id1} or
id=#{id2}
</select>
//入参类型: Map
Map<String,Object> paras = new HashMap();
paras.put("id1", 131);
paras.put("id2", 132);
List<User>
list=session.selectList("com.yjxxt.mapper.UserMapper.queryUserByIdMap",
paras);
list.forEach(System.out::println);
10.3.5. 数组|List
<!-- 参数为数组 根据多个用户名查询用户信息-->
<select id="queryByArray" resultType="User">
select <include refid="user_all_field"/> from t_user where uname in(
<!--
foreach 遍历参数
collection="array" array遍历数组参数
item : 每次遍历获取的数据值
list集合
separator : 分隔符(每次遍历的数据使用分隔符进行连接)
-->
<foreach collection="array" item ="item" separator=",">
#{item}
</foreach>
)
</select>
//Array
String[] arr={"hahaha","zhangsan","lisi"};
List<User>
list=session.selectList("com.yjxxt.mapper.UserMapper.queryByArray",
arr);
list.forEach(System.out::println);
11. 工具类的封装
package com.yjxxt.utils;
import java.io.IOException;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisUtils {
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(); //默认手动提交事务
session = factory.openSession(true); //自动提交
}
return session;
}
}
12. 事务(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;
}
13. 增删改操作
SQL映射文件:
<mapper namespace="com.yjxxt.mappers.UserMapper2">
<!-- 测试增删改 : 结果返回的都是影响函数int -->
<!-- 新增 -->
<insert id="insertUser" parameterType="user">
insert into tb_user values(seq_user_id.nextval,#{username},#{userpwd})
</insert>
<!-- 修改 -->
<update id="updateUser" parameterType="user">
update tb_user set userpwd = #{userpwd} where id =#{id}
</update>
<!-- 删除 -->
<delete id="deleteUser" parameterType="_int">
delete from tb_user where id = #{haha}
</delete>
</mapper>
Java测试类:
/*
* 测试增删改功能
*/
public class UserTest02 {
//删除方法
@Test
public void testDelete() {
SqlSession session = MybatisUtils.getSession();
int rows = session.update("com.yjxxt.mappers.UserMapper2.deleteUser",
100);
if(rows>0) {
System.out.println("SECCESS!!!");
}else {
System.out.println("FAILED!!!");
}
//会话关闭
session.close();
}
//修改方法
@Test
public void testUpdate() {
SqlSession session = MybatisUtils.getSession();
User user = new User();
user.setId(100);
user.setUserpwd(9876);
int rows = session.update("com.yjxxt.mappers.UserMapper2.updateUser",
user);
if(rows>0) {
System.out.println("SECCESS!!!");
}else {
System.out.println("FAILED!!!");
}
//会话关闭
session.close();
}
//插入方法
@Test
public void testInsert() {
SqlSession session = MybatisUtils.getSession();
User user = new User();
user.setUsername("zhangsan");
user.setUserpwd(789);
//插入方法
int rows = session.insert("com.yjxxt.mappers.UserMapper2.insertUser",
user);
//影响行数判断
if(rows>0) {
System.out.println("SECCESS!!!");
//session.commit(); //事务提交
}else {
System.out.println("FAILED!!!");
//session.rollback();
}
//会话关闭
session.close();
}
}
14. resultType结果类型
基本数据类型(包装类) String Date JavaBean List Map List-Map
14.1. Date类型
<!-- Date : 根据id获取生日 -->
<select id="queryDateById" resultType="date"
parameterType="int">
select birthday from t_user where id = #{param1}
</select>
/*
* Date : 根据id返回生日
*/
@Test
public void testDate(){
SqlSession session = MybatisUtils.getSession();
Date date =
session.selectOne("com.yjxxt.mapper.UserMapper.queryDateById",129);
System.out.println(new SimpleDateFormat().format(date));
session.close();
}
14.2. List类型
<!--List类型 :查询指定名字类型的用户信息 -->
<select id="queryUserByUsernameLike" resultType="user"
parameterType="string">
select * from t_user where uname like '%'||#{0}||'%'
</select>
/*
* List : 查询指定名字类型的用户信息
*/
@Test
public void testList(){
SqlSession session = MybatisUtils.getSession();
List<User> list =
session.selectList("com.yjxxt.mapper.UserMapper.queryUserByUsernameLike","i");
list.forEach(System.out::println);
session.close();
}
14.3. Map类型
<!-- Map: 根据用户名和密码查询用户信息 (只能匹配一个用户信息)-->
<select id="queryUserByNamePwdToMap" parameterType="User"
resultType="map">
select * from t_user where uname = #{uname} and upwd = #{upwd}
</select>
/*
* Map : 根据用户名和密码查询用户信息
*
返回值: key 属性名
value 属性值
*
*/
@Test
public void testMap(){
SqlSession session = MybatisUtils.getSession();
Map<String,Object> map=
session.selectOne("com.yjxxt.mapper.UserMapper.queryUserByNamePwdToMap",new
User("yinwei","1314"));
System.out.println(map);
session.close();
}
14.4. List-Map类型
<!-- Map: 根据用户名和密码查询用户信息 (只能匹配一个用户信息)-->
<select id="queryUserByNamePwdToMap" parameterType="User"
resultType="map">
select * from t_user where uname = #{uname} and upwd = #{upwd}
</select>
/*
* List<Map> : 根据用户名和密码查询用户信息,返回多个值
*
返回值: key 属性名
value 属性值
*
*/
@Test
public void testListMap(){
SqlSession session = MybatisUtils.getSession();
List<Map<String,Object>> map=
session.selectList("com.yjxxt.mapper.UserMapper.queryUserByNamePwdToMap",new
User("zhangsan","1234"));
System.out.println(map);
session.close();
}
15. 接口绑定方案
Myabtis中,提供了一套接口绑定方案,程序员可以提供一个接口,然后提供一个与接口所对应的
mapper.xml文件
Myabaits会自动讲接口与xml文件进行绑定,实际上就是Mybatis互根据接口和对应的xml文件创建一个接
口的实现类,换言之,就是可以得到接口实现类的一个对象,方便方法的调用
15.1. 实现方式
15.1.1. 定义接口
/*
* 接口 定义了对用户的操作
*/
public interface UserMapper {
//查询所有用户
public List<User> queryAll();
}
15.1.2. 映射文件
注意:
1. xml文件名要与接口名保持一致
2. namespace属性值 必须与接口的权限定名
3. id属性必须与抽象方法名保持一致
4. 返回值类型和参数类型与方法的返回值和参数保持一致
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTDPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace: 对应的接口的权限定名相同 -->
<mapper namespace ="com.yjxxt.mapper.UserMapper">
<!-- id 与 方法名一致 -->
<select id="queryAll" resultType="User">
select * from t_user
</select>
</mapper>
15.1.3. 在核心配置文件中扫描接口
1) 扫描单个接口,可以使用mapper标签的class属性
<!-- mapper 配置扫描接口 -->
<mappers>
<mapper class="com.yjxxt.mapper.UserMapper"/> <!--配置某个接口
-->
</mappers>
2) 扫描多个接口,可以简化配置,使用package标签,表示扫描对应包下的所有接口
<!-- mapper 配置扫描接口 -->
<mappers>
<package name="com.yjxxt.mapper"/>
</mappers>
15.1.4. 使用
在使用时,通过SqlSession的getMapper()
方法,返回接口代理对象,从而调用以实现的抽象方法
/*
* 测试接口绑定
*/
@Test
public void test(){
SqlSession session = MybatisUtils.getSession();
//getMapper()获取接口实现类对象,参数为接口的class对象,通过参数指定接口
UserMapper mapper =session.getMapper(UserMapper.class);
//通过对象调用方法
List<User> list = mapper.queryAll();
System.out.println(list);
session.close();
}
15.2. 通过接口绑定解决多参数传递问题
15.2.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>
15.2.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>
16. 接口代理开发(CRUD)
//测试接口绑定方案crud
public interface UserMapper {
//查询所有用于信息
public List<User> queryUserByNamePwd(@Param("name") String
name,@Param("pwd") int pwd);
//新增用户
public int addUser(String name,int pwd);
//修改用户信息
public int updateUser(User user);
//删除用户
public int deleteUser(int id);
}
<mapper namespace="com.yjxxt.mappers.UserMapper">
<select id="queryUserByNamePwd" resultType="User">
select * from t_user where username=#{name} or userpwd = #{pwd}
</select>
<!-- 新增用户 -->
<insert id="addUser">
INSERT INTO T_USER VALUES(seq_user_id.nextval,#{param1},#{param2})
</insert>
<!-- 修改用户 -->
<update id="updateUser" parameterType="User">
update t_user set username=#{username},userpwd=#{userpwd} where
id=#{id}
</update>
<!-- 删除用户 -->
<delete id="deleteUser" parameterType="int">
delete from t_user where id=#{id}
</delete>
</mapper>
/*
* 接口实现crud
*/
public class UserTest {
@Test
public void testDelete() {
SqlSession session = MybatisUtils.getSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
int rows = userMapper.deleteUser(202);
if(rows>0) {
System.out.println("成功");
}else {
System.out.println("失败");
}
session.close();
}
@Test
public void testUpdate() {
SqlSession session = MybatisUtils.getSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
int rows = userMapper.updateUser(new User(201,"张三丰",1111));
if(rows>0) {
System.out.println("成功");
}else {
System.out.println("失败");
}
session.close();
}
@Test
public void testInsert() {
SqlSession session = MybatisUtils.getSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
int rows = userMapper.addUser("林更新", 45678);
if(rows>0) {
System.out.println("成功");
}else {
System.out.println("失败");
}
session.close();
}
@Test
public void testSelect() {
SqlSession session = MybatisUtils.getSession();
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> list = userMapper.queryUserByNamePwd("胡歌", 789);
System.out.println(list);
session.close();
}
}
17. 动态 SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC
或其它类似的框架,你应该能理解根据不同
条件拼接 SQL
语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个
列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态
SQL 语言,MyBatis 显
著地提升了这一特性的易用性。
17.1. if
用于进行条件判断, test 属性用于指定判断条件. 为了拼接条件, 在 SQL
语句后强行添加 1=1 的恒成立条
件
<select id="sel" resultType="user">
select * from t_user where 1=1
<if test="username != null and username != ''"> and
username=#{username}
</if>
<if test="password != null and password != ''"> and
password=#{password}
</if>
</select>
17.2. where
用于管理 where 子句. 有如下功能:
1. 如果没有条件, 不会生成 where 关键字
2. 如果有条件, 会自动添加 where 关键字
3. 如果第一个条件中有 and, 去除之
<select id="sel" resultType="user">
select * from t_user
<where>
<if test="username != null and username != ''"> and
username=#{username}
</if>
<if test="password != null and password != ''"> and
password=#{password}
</if>
</where>
</select>
17.3. choose...when...otherwise
这是一套标签, 功能类似于 switch...case...
<select id="sel" resultType="user">
select * from t_user
<where>
<choose>
<when test="username != null and username != ''">
and username = #{username}
</when>
<when test="password != null and password != ''">
and password = #{password}
</when>
<otherwise> and 1=1 </otherwise>
</choose>
</where>
</select>
17.4. set
用于维护 update 语句中的 set 子句. 功能如下:
1. 满足条件时, 会自动添加 set 关键字
2. 会去除 set 子句中多余的逗号
3. 不满足条件时, 不会生成 set 关键字
int updUser(User user);
<update id="updUser" parameterType="user">
update t_user
<set>
id=#{id},<!-- 防止所有条件不成立时的语法错误 -->
<if test="username != null and username != ''">
username=#{username},
</if>
<if test="password != null and password != ''">
password=#{password},
</if>
</set>
where id=#{id}
</update>
17.5. trim
用于在前后添加或删除一些内容
1. prefix, 在前面添加内容
2. prefixOverrides, 从前面去除内容
3. suffix, 向后面添加内容
4. suffixOverrides, 从后面去除内容
<update id="updUser" parameterType="user">
update t_user
<!-- prefix: 前缀, 表示向前面添加内容 prefixOverrides: 从前面删除内容
suffix: 后缀,
表示向后面添加内容 suffixOverrides: 从后面删除内容 -->
<trim prefix="set" prefixOverrides="user" suffix="hahaha"
suffixOverrides=","> username=#{username},
</trim>
where id=#{id}
</update>
17.6. bind
用于对数据进行再加工, 用于模糊查询
<select id="sel" resultType="user">
select * from t_user
<where>
<if test="username!=null and username!=''">
<bind name="username" value="'%' + username + '%'" />
and username like #{username}
</if>
</where>
</select>
17.7. foreach
用于在 SQL 语句中遍历集合参数, 在 in 查询中使用
1. collection: 待遍历的集合
2. open: 设置开始符号
3. item: 迭代变量
4. separator: 项目分隔符
5. close: 设置结束符
List<User> selIn(@Param("list") List<Integer> list);
<select id="selIn" parameterType="list" resultType="user">
select * from t_user where id in
<foreach collection="list" open="(" separator="," close=")"
item="item"> #{item} </foreach>
</select>
17.8. sql...include
sql用于提取 SQL 语句, include用于引用 SQL 语句
<sql id="mySql"> id, username, password </sql>
<select id="selIn" parameterType="list" resultType="user">
select
<include refid="mySql" />
from t_user where id in
<foreach collection="list" open="(" separator="," close=")"
item="item"> #{item}
</foreach>
</select>
18. Mybatis缓存机制
缓存的重要性是不言而喻的。 使用缓存,
我们可以避免频繁的与数据库进行交互, 尤其是在查询越
多、缓存命中率越高的情况下, 使用缓存对性能的提高更明显。
mybatis 也提供了对缓存的支持, 分为一级缓存和二级缓存。
但是在默认的情况下, 只开启一级缓
存。
18.1. 一级缓存
1. 默认开启. 线程级别的缓存, SqlSession 的缓存;
2. 在一个 SqlSession 生命周期中有效. SqlSession 关闭,缓存清空;
3. 在同一个 SqlSession 中, Mybatis
会把执行的方法和参数通过算法生成缓存的键值, 将键值和结果
存放在一个 Map 中, 如果后续的键值一样, 则直接从 Map 中获取数据;
4. 不同的 SqlSession 之间的缓存是相互隔离的;
5. 用一个 SqlSession,
可以通过配置使得在查询前清空缓存;flushCache="true"
6. 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。
18.2. 二级缓存
1. 进程级别的缓存, SqlSessionFactory 的缓存
2. 在一个SqlSessionFactory生命周期中有效. 可以在多个SqlSession
生命中期中共享.
3. 默认关闭, 需要使用的时候, 要为某个命名空间开启二级缓存(在 mapper.xml
中配置cache).
<!-- 开启二级缓存, 要求实体类进行序列化 -->
<cache />
4. 由于在更新时会刷新缓存, 因此需要注意使用场合:查询频率很高,
更新频率很低时使用, 即经
常使用 select, 相对较少使用delete, insert, update。
5. 缓存是以 namespace 为单位的,不同 namespace
下的操作互不影响。但刷新缓存是刷新整个
namespace 的缓存, 也就是你 update 了一个, 则整个缓存都刷新了。
6. 最好在 「只有单表操作」 的表的 namespace 使用缓存,
而且对该表的操作都在这个 namespace
中。 否则可能会出现数据不一致的情况。
二级缓存应用场景:
对于访问多的查询请求并且用户对查询结果实时性要求不高的情况下,可采用mybatis二级缓存,降低
数据库访问量,提高访问速度,如电话账单查询
根据需求设置相应的flushInterval:刷新间隔时间,比如三十分钟,24小时等。。
19. 列名和属性名不一致问题
如果查询时使用 resultType 属性, 表示采用 MyBatis
的Auto-Mapping(自动映射)机制, 即相同的列名和
属性名会自动匹配. 因此, 当数据库表的列名和类的属性名不一致时,
会导致查不到数据. 解决该问题可以
有两种方式:
查询时, 可以通过列别名的方式将列名和属性名保持一致,继续使用自动映射,
从而解决该问题. 但是较为
麻烦.
<select id="selAll" resultType="user">
select id id1, username username1, password password2 from t_user
</select>
20. 使用resultMap
resultMap用于自定义映射关系, 可以由程序员自主制定列名和属性名的映射关系.
一旦使用 resultMap,
表示不再采用自动映射机制.
<resultMap type="user" id="umap">
<!-- id用于映射主键 -->
<id column="id" property="id1" />
<!-- 非主键使用result映射 -->
<result column="username" property="username1" />
<result column="password" property="password1" />
</resultMap>
<select id="selAll" resultMap="umap"> select * from t_user
</select>
20.1. 关系映射查询
数据库中表与表之间的关系:
一对一 (人->身份证)
一对多 (夏令营->学生)
多对一 (学生->班级)
多对多 (学生->课程)
20.2. resultMap 的关联方式实现多表查询(一对一|多对一)
1. 在 StudentMapper.xml 中定义多表连接查询 SQL 语句,
一次性查到需要的所有数据, 包括对应班级
的信息.
2. 通过resultMap标签定义映射关系,
并通过association标签指定对象属性的映射关系. 可以把
association标签看成一个resultMap标签使用. javaType 属性表示当前对象,
可以写全限定路径或
别名.
学生类中添加一个班级类型的属性 :
public class Student implements Serializable{
private int id;
private String name;
private int age;
private String gender;
private int cid;
private Clazz cls;
}
StudentMapper:
<resultMap type="student" id="smap">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
<association property="cls" javaType="clazz">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
</association>
</resultMap>
<select id="selAll" resultMap="smap">
select s.id sid, s.name sname,
s.age, s.gender, c.id cid, c.name cname, c.room from t_student s left
join t_class c on s.cid=c.id
</select>
20.3. resultMap 的关联方式实现多表查询(一对 多)
1. 在 ClazzMapper.xml 中定义多表连接查询 SQL 语句,
一次性查到需要的所有数据, 包括对应学生的
信息.
2. 通过resultMap定义映射关系,
并通过collection标签指定集合属性泛型的映射关系. 可以collection
标签看成一个resultMap标签使用. ofType 属性表示集合的泛型,
可以写全限定路径或别名.
班级类中添加一个List容器存储学生类型 的数据 :
public class Clazz implements Serializable{
private int id;
private String name;
private int roomNum;
private List<Student> stus;
}
ClazzMapper.xml:
<mapper namespace="com.yjxxt.mapper.ClazzMapper">
<resultMap type="clazz" id="cmap">
<id property="id" column="cid" />
<result property="name" column="cname" />
<result property="room" column="room" />
<collection property="stus" javaType="list"
ofType="student">
<id property="id" column="sid" />
<result property="name" column="sname" />
<result property="age" column="age" />
<result property="gender" column="gender" />
<result property="cid" column="cid" />
</collection>
</resultMap>
<select id="selAll" resultMap="cmap">
select c.id cid, c.name cname,
c.room, s.id sid, s.name sname, s.age, s.gender from t_student s right
join t_class c on s.cid=c.id </select>
</mapper>
21. 注解开发
21.1. Mybatis中注解的作用
使用注解一般用于简化配置文件. 但是,
注解有时候也不是很友好(有时候反而更麻烦), 例如动态 SQL等,所
以注解和配置文件可以配合使用
21.2. MyBatis 中常用的注解
21.2.1. CRUD 注解
@Select: 类似于select标签
@Insert: 类似于insert标签
@Update: 类似于update标签
@Delete: 类似于delete标签
package com.yjxxt.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.yjxxt.pojo.Student;
public interface StudentMapper {
@Select("select * from t_student")
List<Student> selAll();
@Insert("insert into t_student values (default, #{name}, #{age},
#{gender},
#{cid})")
int insStu(Student student);
@Update("update t_student set age=#{1} where id=#{0}")
int updStu(int id, int age);
@Delete("delete from t_student where id=#{0}")
int delStu(int id);
}
21.2.2. 其他注解
@Results: 类似于resultMap标签
@Result: 类似<resultMap的子标签
@One: 类似于association标签
@Many: 类似于collection标签
public interface StudentMapper {
@Select("select * from t_student")
@Results(
value = { @Result(column="id", property="id", id=true),
@Result(column="name", property="name"),
@Result(column="age", property="age"),
@Result(column="gender", property="gender"),
@Result(column="cid", property="cid"),
@Result(property="clazz",
one=@One(select="com.yjxxt.mapper.ClazzMapper.selById"),
column="cid")
}
)
List<Student> sel();
}
public interface ClazzMapper {
@Select("select * from t_class where id=#{0}")
Clazz selById(int id);
}
22. 逆向工程
mybatis-generator是一款mybatis自动代码生成工具,可以通过配置,快速生成pojo,mapper和xml文件.
官方网址:http://mybatis.org/generator/configreference/xmlconfig.html
generatorConfig.xml配置
需添加到资源包下 src下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator
Configuration 1.0//EN"
config_1_0.dtd">
"http://mybatis.org/dtd/mybatis-generator-
<generatorConfiguration>
<!--数据库驱动 -->
<context id="Tables" targetRuntime="MyBatis3">
<!-- 生成的Java文件的编码 -->
<property name="javaFileEncoding" value="UTF-8" />
<!-- JavaBean 实现 序列化 接口 -->
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"/>
<commentGenerator>
<property name="suppressDate" value="true" />
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="false" />
</commentGenerator>
<!--数据库链接地址账号密码 -->
<jdbcConnection
driverClass="oracle.jdbc.driver.OracleDriver"
connectionURL="jdbc:oracle:thin:@localhost:1521:xe"
userId="SCOTT"
password="TIGER">
</jdbcConnection>
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为
true 时把
JDBC DECIMAL 和 NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--生成 Model 类存放位置 -->
<javaModelGenerator targetPackage="com.yjxxt.pojo"
targetProject="mybatis12\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--生成映射文件存放位置 -->
<sqlMapGenerator targetPackage=\"com.yjxxt.mappers\"
> targetProject=\"mybatis12\\src\"\>
>
> \<property name=\"enableSubPackages\" value=\"true\" /\>
\</sqlMapGenerator\>
\<!\--生成接口类存放位置(Dao\|Mapper) \--\>
\<javaClientGenerator type=\"XMLMAPPER\"
> targetPackage=\"com.yjxxt.mappers\" targetProject=\"mybatis12\\src\"\>
>
> \<property name=\"enableSubPackages\" value=\"true\" /\>
\</javaClientGenerator\>
\<!\-- 参考数据库中需要生成的对应表信息 \--\>
\<table tableName=\"dept\" domainObjectName=\"Dept\"
> enableCountByExample=\"false\" enableUpdateByExample=\"false\"
>
> enableDeleteByExample=\"false\" enableSelectByExample=\"false\"
>
> selectByExampleQueryId=\"false\"\>\</table\>
\<table tableName=\"emp\" domainObjectName=\"Emp\"
> enableCountByExample=\"false\" enableUpdateByExample=\"false\"
>
> enableDeleteByExample=\"false\" enableSelectByExample=\"false\"
>
> selectByExampleQueryId=\"false\"\>\</table\>
\</context\>
\</generatorConfiguration\>