1.Mybatis的介绍
mybatis就是一个封装jdbc的持久层框架,它和hibernate都属于ORM框架,但是具体的说,hibernate是一个完全的orm框架,而mybatis是一个不完全的orm框架。mybatis让程序员只关注sql本身,而不需要去关注如连接的创建、statement的创建等操作。mybatis会将输入参数、输出结果进行映射。
2.Mybatis的框架原理
3.下载Mybatis
mybaits的代码由github.com管理,下载地址:https://github.com/mybatis/mybatis-3/releases
4.入门程序
- 4.1工程搭建
Mybatis的核心包和依赖包
MySQl的驱动包
Junit(非必须)
- 4.2代码实现
1)创建pojo类
public class User {
private Integer id;
private String userName; //用户名
private String sex; //性别
private String birthday; //生日
private String address; //地址
省略getXxx()和setXxx()
...
}
2)创建全局配置文件
在config目录下,创建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">
<!-- 对类进行别名的定义 -->
<typeAliases>
<!-- 单个别名定义 -->
<!-- <typeAlias type="com.mybatis.assess.pojo.User" alias="user" /> -->
<!-- 批量别名定义 -->
<!-- package:指定包名称来为该包下的pojo类声明别名,默认的别名就是类名(首字母大小写都行)-->
<package name="com.mybatis.assess.pojo"/>
</typeAliases>
<configuration>
<!--配置mybatis的环境信息,与spring整合,该信息由spring管理 -->
<environments default="development">
<environment id="development">
<!-- 配置jdbc事物控制,由mybatis管理 -->
<transactionManager type="JDBC" />
<!-- 配置数据源,采用mybatis连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<configuration>
<!-- 加载映射文件 -->
<mappers>
<!-- 使用相对于类路径的资源 -->
<mapper resource="com/mybatis/assess/config/UserMapper.xml"/>
</mappers>
3)映射文件
在config目录下,创建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">
<!-- 注意:在mapper代理时,它具有特殊及重要的作用 -->
<mapper namespace="IUserMapper">
<!-- select:表示一个MappedStatement对象
id:statement的唯一标识
#{}:表示一个占位符?
#{id}:里面的id表示输入参数的参数名称,如果该参数是简单类型,那么#{}参数名称可以任意
parameterType:输入参数的JAVA类型
resultType:输出结果所映射的java类型(单条结果所对应的java类型)
-->
<select id="queryUserById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
<!-- ${}:表示一个sql的连接符
${value}:里面的value表示输入参数的名称,如果该参数是简单类型,那么${}里面的参数名称必须是value
${}:这种写法存在sql注入的风险,但是在一定的场景下,必须使用${},比如排序时,动态传入排序的名称
-->
<select id="queryUserByName" parameterType="String" resultType="User">
select * from User where username like '%${value}%'
</select>
<!-- 主键自增长 并且配置 useGeneratedKeys="true" keyProperty="fid" -->
<insert id="insertUser" parameterType="user" useGeneratedKeys="true"
keyProperty="id">
insert into
user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 主键返回之自增主键
selectkey:查询主键,在标签内需要输入查询主键的sql
order:指定查询主键的sql和insert语句的执行顺序,相当于insert语句来说
LAST_INSERT_ID:该函数是mysql的函数,获取自增主键的id,它必须配合insert语句一起使用
-->
<insert id="saveUser" parameterType="user">
<selectKey keyProperty="id" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into
user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 自增主键之UUID -->
<insert id="saveUser2" parameterType="user">
<selectKey keyProperty="id" resultType="String" order="BEFORE"><!-- 只要不是自增主键,那么order都设置为before -->
select UUID()
</selectKey>
insert into
user(id,username,birthday,sex,address) values (#{id},#{username},#{birthday},#{sex},#{address})
<!-- 需要显示的给id赋值,因为该id的值不是通过自增主键来创建的 -->
</insert>
注意:最后需要在全局配置文件中加载映射文件
4)测试代码
##根据用户ID查询用户信息
@Test
public void test() throws Exception{
//读取配置文件
String resource = "com/mybatis/assess/config/SqlMapConfig.xml";
Reader reader = Resources.getResourceAsReader(resource);
//创建sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//第一个参数,表示statement的唯一标识
User user = sqlSession.selectOne("IUserMapper.queryUserById", 1);
System.out.println(user.getUserName());
//关闭资源
sqlSession.close();
}
##根据用户名称模糊查询用户列表
@Test
public void test() throws Exception{
.....
//第一个参数,表示statement的唯一标识
Object object = sqlSession.selectList("IUserMapper.queryUserByName", "张");
System.out.println(object);
//关闭资源
.....
}
##添加用户
@Test
public void test() throws Exception{
.....
//第一个参数,表示statement的唯一标识
User user = new User();
user.setUsername("Jello");
user.setSex("1");
user.setBirthday("2016-08-08");
user.setAddress("上海市");
sqlSession.insert("IUserMapper.insertUser", user);
//提交事务
sqlSession.commit();
//关闭资源
.....
}
5.Mapper代理的开发方式
开发mapper接口(相当于dao接口),Mapper代理使用的是jdk的代理策略。
5.1Mapper代理的开发规范
mapper接口的全限定名要和mapper映射文件的namespace值一致。
mapper接口的方法名称要和mapper映射文件的statement的id一致。
mapper接口的方法参数类型要和mapper映射文件的statement的parameterType的值一致,而且它的参数是一个。
mapper接口的方法返回值类型要和mapper映射文件的statement的resultType的值一致。5.2mapper接口
public interface UserMapper {
int saveUser(User user) throws Exception;
User queryUserById(Integer id) throws Exception;
}
- 5.3mapper映射文件
在com.mybatis.assess.mybatis下创建UserMapper.xml(这是mybatis的命名规范,当然,也不是必须是这个名称)
sqlSession内部的数据区域本身就是一级缓存,是通过map来存储的。
<?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.mybatis.assess.dao.UserMapper">
<!-- 根据用户ID查询 -->
<select id="queryUserById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
<!-- 添加用户 -->
<insert id="saveUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into user(username,sex,birthday,address)
values (#{username},#{sex},#{birthday},#{address})
</insert>
</mapper>
5.4加载映射文件
5.5测试代码
public static SqlSessionFactory getSqlSessionFactory(){
//读取配置文件
String resource = "SqlMapConfig.xml";
Reader reader = null;;
SqlSessionFactory sqlSessionFactory = null;
try {
reader = Resources.getResourceAsReader(resource);
//创建sqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
return sqlSessionFactory;
}
/**
* 根据ID查询用户
* @throws Exception
*/
@Test
public void queryUserById() throws Exception{
SqlSession sqlSession = getSqlSessionFactory().openSession();
User user = sqlSession.selectOne("com.mybatis.assess.dao.UserMapper.queryUserById", 1);
System.out.println(user.toString());
//关闭资源
sqlSession.close();
}
6.全局配置文件
6.1概览
SqlMapConfig.xml的配置内容和顺序如下(顺序不能乱):
Properties(属性)
Settings(全局参数设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境信息集合)
environment(单个环境信息)
transactionManager(事物)
dataSource(数据源)
mappers(映射器)6.2常用配置
1.properties
加载的顺序
1)先加载properties中property标签声明的属性
2)再加载properties标签引入的java配置文件中的属性
3)parameterType的值会和properties的属性值发生冲突。
2.settings
mybatis全局配置参数,全局参数将会影响mybatis的运行行为
3.typeAliases
对pojo类进行别名的定义
4.mybatis支持的别名
自定义别名:
5.Mappers
<mappers>
<!-- 使用相对于类路径的资源 -->
<mapper resource="com/mybatis/assess/config/UserMapper.xml"/>
<mapper url=’’/> 使用完全限定路径
<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\UserMapper.xml" />
<mapper class=’’/> 使用mapper接口的全限定名
<mapper class="com.mybatis.mapper.UserMapper"/>
此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下;
<package name=’’/>(推荐)
注册指定包下的所有映射文件
<package name="cn.mybatis.mapper"/>
此种方法要求mapper接口和mapper映射文件要名称相同,且放到同一个目录下;
</mappers>
7.映射文件
7.1输入映射parameterType
简单类型
Pojo类型
包装pojo类型Map
同传递POJO对象一样,map的key相当于pojo的属性。
映射文件:
上边红色标注的是hashmap的key。
测试代码:
异常测试:
传递的map中的key和sql中解析的key不一致。测试结果没有报错,只是通过key获取值为空。7.2输出映射resultType
1)使用要求
使用resultType进行结果映射时,需要查询出的列名和映射的对象的属性名一致,才能映射成功。
如果查询的列名和对象的属性名全部不一致,那么映射的对象为空。
如果查询的列名和对象的属性名有一个一致,那么映射的对象不为空,但是只有映射正确那一个属性才有值。
如果查询的sql的列名有别名,那么这个别名就是和属性映射的列名。
2) 简单类型
注意:对简单类型的结果映射也是有要求的,查询的列必须是一列,才能映射为简单类型。
mapper接口:
测试代码:
@Test
public void queryCount() throws Exception{
SqlSession sqlSession = getSqlSessionFactory().openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int count = mapper.queryCount();
System.out.println(count);
//关闭资源
sqlSession.close();
}
3)Pojo对象和pojo列表
4)resultMap
使用要求:使用resultMap进行结果映射时,不需要查询的列名和映射的属性名必须一致。但是需要声明一个resultMap,来对列名和属性名进行映射。
映射文件:
<resultMap type="User" id="userRstMap">
<!-- id:专门为查询结果中唯一列映射 result:映射查询结果中的普通列 -->
<id column="id" property="id"/>
<result column="username" property="username" />
<result column="sex" property="sex" />
<result column="birthday" property="birthday" />
<result column="address" property="address" />
</resultMap>
<select id="queryAllUser" resultMap="userRstMap">
select * from user
</select>
测试代码:
@Test
public void queryAllUser() throws Exception{
SqlSession sqlSession = getSqlSessionFactory().openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user = mapper.queryAllUser();
System.out.println(user.toString());
//关闭资源
sqlSession.close();
}
- 7.3动态sql
在mybatis中,它提供了一些动态sql标签,可以让程序员更快的进行mybatis的开发,这些动态sql可以通过sql的可重用性。
常用的动态sql标签:if标签、where标签、sql片段、foreach标签
1)If标签/where标签和sql片段(Sql片段可以让代码有更高的可重用性、Sql片段需要先定义后使用)
映射文件:
<!-- 定义sql片段
sql片段内,可以定义sql语句中任何部分
sql片段内,最好不要将where和select关键字声明在内-->
<sql id="whereClause">
<!-- if:可以对输入的参数进行判断 test:指定判断表达式 -->
<if test="userName!=null and userName!=''">
and userName like '%${userName}%'
</if>
<if test="birthday!=null and birthday!=''">
and birthday = #{birthday};
</if>
</sql>
<select id="queryUserByNameOrBirthday" parameterType="User" resultType="User">
select * from user
<!-- where:默认去掉后面第一个and 如果没有参数,则把自己干掉 -->
<where>
<!-- 引入sql片段 -->
<include refid="whereClause"></include>
</where>
</select>
测试代码:
@Test
public void queryUserByNameOrBirthday() throws Exception{
SqlSession sqlSession = getSqlSessionFactory().openSession();
User uu =new User();
uu.setBirthday("");
uu.setUserName("王五");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user = mapper.queryUserByNameOrBirthday(uu);
System.out.println(user.size());
//关闭资源
sqlSession.close();
}
2)Foreach标签
可以循环传入参数值
映射文件:
<sql id="foreachCaluse">
and id in
<!--
collection:表示pojo中集合属性的名称
item:为遍历出的结果声明一个变量名称
open:遍历开始时,需要拼接的字符串
close:遍历结束时,需要拼接的字符串
separator:遍历中间需要拼接的字符串
-->
<foreach collection="idList" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</sql>
<!-- 根据多个ID查询用户 -->
<select id="queryUserByIds" parameterType="User" resultType="User">
select * from user
<where>
<include refid="foreachCaluse"></include>
</where>
</select>
测试代码:
@Test
public void queryUserByIds() throws Exception{
SqlSession sqlSession = getSqlSessionFactory().openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(10);
User uu =new User();
uu.setIdList(list);
List<User> user = mapper.queryUserByIds(uu);
System.out.println(user.size());
//关闭资源
sqlSession.close();
}
8.mybatis与hibernate的区别及各自应用场景
Mybatis技术特点:
1.通过直接编写SQL语句,可以直接对SQL进行性能的优化;
2.学习门槛低,学习成本低。只要有SQL基础,就可以学习mybatis,而且很容易上手;
3.由于直接编写SQL语句,所以灵活多变,代码维护性更好。
4.不能支持数据库无关性,即数据库发生变更,要写多套代码进行支持,移植性不好。
Hibernate技术特点:
1.标准的orm框架,程序员不需要编写SQL语句。
2.具有良好的数据库无关性,即数据库发生变化的话,代码无需再次编写。
3.学习门槛高,需要对数据关系模型有良好的基础,而且在设置OR映射的时候,需要考虑好性能和对象模型的权衡。
4.程序员不能自主的去进行SQL性能优化。
Mybatis应用场景:
需求多变的互联网项目,例如电商项目。
Hibernate应用场景:
需求明确、业务固定的项目,例如OA项目、ERP项目等。