您的位置:首页 > 其它

mybatis的了解

2018-01-17 19:40 344 查看
一、mybatis的框架结构



过程说明:

1、 mybatis配置

SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。

mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。

2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂

3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。

4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。

5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped
Statement对象,sql的id即是Mapped
statement的id。

6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped
Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。

7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped
Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

注意事项:
1.代码说明

public class User_select {
public static void main(String[] args) throws IOException {

//加载配置文件
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);

//根据mytais的配置创建SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//根据SqlSessionFactory创建SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

//通过sqlSession查询用户信息(发起数据库操作)
//第一个参数statement:指定mapper映射文件中statement的id,指定 时需要前边加上statement所属的命名空间
//第二个参数parameter,指定 输入参数
//selectOne返回的是单条记录,如果select返回多条记录(list集合),使用selectOne会报错
//根据映射文件中的resultType指定输出类型
User user = sqlSession.selectOne("test.findUserById", 10);

//遍历查询结果
System.out.println(user);

//查询用户列表
//selectList表示查询一个结果集(可以是一条或多条)
List<User> list = sqlSession.selectList("test.findUserList", "张");

System.out.println(list.size());

//关闭sqlSession

sqlSession.close();

}
}

2、sqlSession的使用注意事项

SqlSession使用方法

SqlSessionFactoryBuilder:用于创建SqlSessionFactory,将SqlSessionFactoryBuilder当成工具类使用。

 

SqlSessionFactory:会话工厂,用于创建SqlSession,SqlSessionFactory一旦创建成功,不用每次创建工厂,建议单例模式使用工厂。如果和spring整合后,由spring来管理SqlSessionFactory,在spring容器中SqlSessionFactory是一个单例对象

 

SqlSession:(重点)是一个面向用户的接口,通过SqlSessionFactory获取SqlSession,每次数据操作都需要创建新的SqlSession,SqlSession
不是线程安全,最佳应用场合是方法体内,在方法中定义一个SqlSession局部变量。


二、mybatis作为持久层框架在开发过程中常用的两种配置方式

1、原始dao层的使用方式

这种情况:需要开发dao接口和dao的实现类。

public interface UserDao {

//根据用户id查询用户信息
public User findUserById(int id) throws Exception;

//添加用户
public void insertUser(User user) throws Exception;

//查询用户列表
public List<User> findUserList()throws Exception;
}
public class UserDaoImpl implements UserDao {

// 注入SqlSessionFactory
private SqlSessionFactory sqlSessionFactory;

public UserDa
14f0e
oImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}

@Override
public User findUserById(int id) throws Exception {

// 根据SqlSessionFactory创建SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

// 通过sqlSession查询用户信息(发起数据库操作)
// 第一个参数statement:指定mapper映射文件中statement的id,指定 时需要前边加上statement所属的命名空间
// 第二个参数parameter,指定 输入参数
// selectOne返回的是单条记录,如果select返回多条记录(list集合),使用selectOne会报错
// 根据映射文件中的resultType指定输出类型
User user = sqlSession.selectOne("test.findUserById", id);

// 遍历查询结果
// System.out.println(user);

return user;
}

@Override
public void insertUser(User user) throws Exception {
// 根据SqlSessionFactory创建SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

sqlSession.insert("test.insertUser", user);

sqlSession.commit();

sqlSession.close();

}

@Override
public List<User> findUserList() throws Exception {
// 根据SqlSessionFactory创建SqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

// 通过sqlSession查询用户信息(发起数据库操作)
// 第一个参数statement:指定mapper映射文件中statement的id,指定 时需要前边加上statement所属的命名空间
// 第二个参数parameter,指定 输入参数
// selectOne返回的是单条记录,如果select返回多条记录(list集合),使用selectOne会报错
// 根据映射文件中的resultType指定输出类型

// 查询用户列表
// selectList表示查询一个结果集(可以是一条或多条)
List<User> list = sqlSession.selectList("test.findUserList", "张");

System.out.println(list.size());
return list;
}

}


具体代码参考:https://github.com/libolibolibo/mybatis1217_1.git

2、使用mybatis的动态代理的方法

2.1、使用mybatis动态代理的好处

在开发过程中,只需要开发dao接口、接口对应的mapper.xml文件就可以了;

2.2、使用mybatis动态代理开发的原理

通过mybatis动态代理规则的配置,根据映射文件会生成dao接口实现类的代理对象,这个就相当于mybatis自己通过映射文件的配置,自己生成类dao接口的实现类,进而动态的调用statement语句;

2.3、使用mybatis的动态代理的规则配置

2.31、 在mapper.xml中将namespace设置为mapper.java接口的全限定名

2.32、 将mapper.java接口的方法名和mapper.xml中statement的id保持一致。

2.33、 将mapper.java接口的方法输入参数类型和mapper.xml中statement的parameterType保持一致

2.34、 将mapper.java接口的方法输出 结果类型和mapper.xml中statement的resultType保持一致

2.4注意:mybatis在调用查询的时候是调用selectOne还是selectList取决于dao接口的返回值,但是resultType保持不变;

Mybatis生成代理对象时,根据statement的标签决定调用
SqlSession的方法(select、insert、update..)
根据上边接口方法返回值
类型来决定 是调用 selectOne还是selectList,如果返回的是单个对象,动态代理调用selectOne(),如果返回的是集合对象,动态代理调用selectList()。
<select id="findUserById" parameterType="int" resultType="user">

SELECT * FROM USER WHERE id = #{id}

</select>
<select id="findUserList" parameterType="java.lang.String" resultType="cn.itcast.mybatis.po.User" >
SELECT * FROM USER WHERE username LIKE '%${value}%'
</select>
public interface UserMapper {

//根据用户id查询用户信息
public User findUserById(int id) throws Exception;

//查询用户列表
public List<User> findUserList(String username)throws Exception;

}


具体的代码示例:https://github.com/libolibolibo/mybatis1217_2.git

三、mybatis框架的全局的配置文件(一般名称为SqlMapConfig.xml)说明,这个在开发过程中使用比较少,一般在与spring整合后就不使用该文件了,但是要了解
1、全局配置文件的作用
SqlMapConfig.xml作为mybatis的全局配置文件,配置内容包括:数据库环境、mapper定义、全局参数设置......

properties(属性)

properties属性文件一般使用在,将数据库连接参数单独在一个properties文件中配置,好处是:方便系统升级维护。

settings(全局配置参数)

mybaits框架运行设置一些全局配置参数,比如:开启二级缓存 ,开启延迟载。。。

在ibatis中有一些设置性能参数(最大线程数、最大请求数。。),在mybatis中没有这些性能参数。

注意:设置全局参数会影响mybatis框架运行,谨慎设置。

typeAliases(类型别名)

在parameterType和resultType设置时,为了方便编码,定义别名代替pojo的全路径。

typeHandlers(类型处理器)

类型处理器用于java类型和jdbc类型映射:

Mybatis提供 的类型处理器满足日常需要。

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器)

<?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>
<!-- 加载数据库连接参数配置文件 -->
<properties resource="db.properties" />

<!-- 全局配置参数 -->
<!-- settings></settings> -->

<!-- 定义别名 -->
<typeAliases>
<!-- 单个别名定义
type:pojo的路径
alias:别名的名称
-->
<!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
<!-- 批量别名定义
name:指定包名,将包下边的所有pojo定义别名 ,别名为类名(首字母大写或小写都行)
-->
<package name="cn.itcast.mybatis.po"/>
</typeAliases>

<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>

<!-- 配置mapper映射文件 -->
<mappers>
<!-- resource方式
在UserMapper.xml,定义namespace为mapper接口的地址,映射文件通过namespace找到对应的mapper接口文件
-->
<!-- <mapper resource="sqlmap/UserMapper.xml" /> -->
<!-- class方式
class:指定 mapper接口的地址
遵循规则:将mapper.xml和mapper.java文件放在一个目录 且文件名相同
-->
<!-- <mapper class="cn.itcast.mybatis.mapper.UserMapper"/> -->

<!--批量mapper扫描
遵循规则:将mapper.xml和mapper.java文件放在一个目录 且文件名相同
-->
<package name="cn.itcast.mybatis.mapper"/>

</mappers>
</configuration>

四、mybatis的映射文件配置说明(一般命名为xxxMapper.xml)
(一)、主键返回问题

需求 :对于新增的记录,需要将主键返回到pojo中,就可以从pojo中获取新添加的记录id。

自增主键生成 Uuid主键生成时机区别:

自增主键在insert语句执行后生成 的。
Uuid主键在insert语句执行前生成 的。

1、Mysql自增主键获取

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">

<!--
keyProperty:将主键设置到pojo中哪个属性中
order:selectKey中sql执行的时机
resultType:selectKey中sql执行的结果类型
LAST_INSERT_ID:是insert后获取自增主键值
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>

insert into user(username,birthday,sex,address,detail,score)
values(#{username},#{birthday},#{sex},#{address},#{detail},#{score})
</insert>

2、 Uuid主键获取

Uuid主键在insert语句执行前生成 的

 

如果使用uuid获取主键,定义selectkey

 <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<!--
keyProperty:将主键设置到pojo中哪个属性中
order:selectKey中sql执行的时机
resultType:selectKey中sql执行的结果类型
LAST_INSERT_ID:是insert后获取自增主键值
-->
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
select uuid()
</selectKey>

insert into user(id,username,birthday,sex,address,detail,score)
values(#{id},#{username},#{birthday},#{sex},#{address},#{detail},#{score})
</insert>
如果不用selectKey,也可以在调用SqlSession.insert()前,在输入参数设置id值
(生成uuid,设置到user的id属性中。)。

3、Oracle主键返回

Oracle没有自增主键,使用oracle的序列(可以生成流水号,类似 自增主键)生成主键。

 

通过序列获取流水号方法:

Select 序列名.next.val from dual

 <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<!--
keyProperty:将主键设置到pojo中哪个属性中
order:selectKey中sql执行的时机
resultType:selectKey中sql执行的结果类型
LAST_INSERT_ID:是insert后获取自增主键值
-->
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
Select 序列名.next.val from dual
</selectKey>

insert into user(id,username,birthday,sex,address,detail,score)
values(#{id},#{username},#{birthday},#{sex},#{address},#{detail},#{score})
</insert>
(二)、parameterType(输入类型)

parameterType:用于设置输入参数的类型。

1、#{}与${}

 

#{}:表示占位符,如果获取简单类型,#{}中可以使用value或其它名称 。有效防止sql注入。使用#{}设置参数无需考虑参数的类型。

如果使用#{}比较日期字段,select * from tablename where birthday >=#{birthday}

 

${}:表示sql拼接,如果获取简单类型,${}中只能使用value
。无法防止sql注入。使用${}设置参数必须考虑参数的类型,比如:使用oracle查询条件是日期类型,如果使用${},必须人为将${}两边加单引号通过to_date转日期。(只是表示简单的字符串拼接,而没有mybatis的映射关系)

Select * from table where birthday >=to_date(‘${birthday}’,’yyyy-MM-dd’)

 

在没有特殊要求的情况下,建议使用#{}占位符

有些情况必须使用${},

比如:需要动态拼接表名,Select * from ${tablename}

动态拼接排序字段:select * from tablename order by ${username} desc

2、 传递pojo对象

2.1、parameterType指定
输入参数为pojo自定义对象时,在sql中使用${}和#{}获取pojo的属性。

 

2.2、 包装对象使用

开发中使用pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(是另一个pojo),使用包装对象传递输入参数。

 

定义包装对象将查询条件(pojo)以类组合的方式包装起来。

 

parameterType使用包装对象:

包装类

public class QueryVo {

//用户查询条件
//为了查询条件扩展方便,基于po的基础上自定义的pojo,继承于Po
private UserCustom userCustom;

private User user;

private int[] ids;

public UserCustom getUserCustom() {
return userCustom;
}

public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

public int[] getIds() {
return ids;
}

public void setIds(int[] ids) {
this.ids = ids;
}

//基它的查询条件

}

public class UserCustom extends User {

//学生类型,扩展字段
private String groupid;

public String getGroupid() {
return groupid;
}

public void setGroupid(String groupid) {
this.groupid = groupid;
}

}


映射文件.xml
<!-- 查询用户列表 根据用户名称和用户性别查询用户列表 -->
<select id="findUserList" parameterType="queryVo" resultType="user">
select id,username username_ from user
<!-- where自动将第一个and去掉 -->
<where>
<!-- 这里调用 queryVo的getUser方法获 取user的值 -->
<if test="user!=null">
<!-- 这里调用 queryVo的user的getUsername方法获取username的值 -->
<if test="user.username!=null and user.username!=''">
and user.username = #{user.username}
</if>
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex}
</if>
</if>
<if test="ids!=null">
<foreach collection="ids" item="id" open="AND ("
separator="OR" close=")">
id =#{id}
</foreach>

<!-- AND id IN (10,89,16) -->
<!-- <foreach collection="ids" item="id" open="AND id IN ("
separator="," close=")">
#{id}
</foreach> -->
</if>
</where>
</select>

2.3、 传递hashmap

parameterType指定 hashmap传递输入参数,#{}和${}中引用map的key。

 

Sql映射文件定义如下:

<!-- 传递hashmap综合查询用户信息 -->
<select id="selectUserByHashmap" parameterType="hashmap" resultType="user">
select * from user where id=#{id} and username like '%${username}%'
</select>


(三)、 resultType输出映射到java对象上

1、返回pojo

resultType:将sql查询结果集映射为java对象。要求sql查询的字段名和resultType指定pojo的属性名一致,才能映射成功。

如果全部字段和pojo的属性名不一致,映射生成 的java对象为空,只要有一个字段和pojo属性名一致,映射生成
的java对象不为空。

 

结论:sql查询字段名和pojo的属性名一致才能映射成功。

 

 

不管select返回的是单个 对象还是集合对象,resultType要指定单条记录映射的java对象。

2、返回简单类型

如果 sql查询的结果集只有一行且一列,resultType可以返回简单类型。

3、 返回hashmap

输出pojo对象可以改用hashmap输出类型,将输出的字段名称作为map的key,value为字段值。

 l Mapper.xml
<select id="findUserListReturnMap" parameterType="queryVo" resultType="hashmap">
select id,username username_ from user where username = #{user.username} and sex=#{user.sex}
</select>
l Mapper.java
Public Map findUserListReturnMap(QueryVo queryVo);
建议不使用map作为返回值 ,因为需要对key在代码中硬编码。

(四)、mybatis的动态sql

Mybatis提供 了很多标签,用于拼接sql语句。

if标签
where标签
set标签
foreach标签
<?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="cn.itcast.mybatis.mapper.UserMapperCustom">

<!-- sql片段 -->
<!--
用户查询条件
id:在namespace唯 一标识
建议以单表抽取查询条件
-->
<sql id="query_user_where">

<!-- 这里调用 queryVo的getUser方法获 取user的值 -->
<if test="user!=null">
<!-- 这里调用 queryVo的user的getUsername方法获取username的值 -->
<if test="user.username!=null and user.username!=''">
and user.username = #{user.username}
</if>
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex}
</if>

</if>
<if test="ids!=null">
<!-- 根据传入id数组构造查询条件 -->
<!-- AND (id =10 OR id =89 OR id=16) -->
<!-- 遍历ids数组

collection:集合,ids数组
item:遍历的每个对象
open:开始遍历时拼接的sql
separator:遍历的间隔符号
close:结束 遍历时拼接的sql
-->
<foreach collection="ids" item="id" open="AND ("
separator="OR" close=")">
id =#{id}
</foreach>

<!-- AND id IN (10,89,16) -->
<!-- <foreach collection="ids" item="id" open="AND id IN ("
separator="," close=")">
#{id}
</foreach> -->
</if>

</sql>

<!-- 定义resultMap,将用户查询的字段和user这个pojo的属性名作一个对应关系 -->
<!--
type:最终映射的java对象。
id:resultMap的唯一标识
-->
<resultMap type="user" id="userListResultMap">
<!-- id标签:查询结果集的唯 一标识 列(主键或唯 一标识 )
column:sql查询字段名(列名)
property:pojo的属性名

result标签:普通列
-->

<id column="id_" property="id"/>
<result column="username_" property="username"/>
<result column="birthday_" property="birthday"/>

</resultMap>

<!-- 查询用户列表 根据用户名称和用户性别查询用户列表 -->
<select id="findUserList" parameterType="queryVo" resultType="user">
select id,username username_ from user

<!-- where自动将第一个and去掉 -->
<where>
<!--
refid:指定 sql片段的id,如果要引用其它命名空间的sql片段,需要前边加namespace

-->
<include refid="query_user_where"/>
</where>
</select>

<!-- 查询用户列表 根据用户名称和用户性别查询用户列表 -->
<select id="findUserListResultMap" parameterType="queryVo" resultMap="userListResultMap">
select id id_,username username_,birthday birthday_ from user

<!-- where自动将第一个and去掉 -->
<where>
<!--
refid:指定 sql片段的id,如果要引用其它命名空间的sql片段,需要前边加namespace

-->
<include refid="query_user_where"/>
</where>
</select>

<!-- 查询用户列表总数 用于分页查询 -->
<select id="findUserCount" parameterType="queryVo" resultType="int">
select count(*) from user
<!-- where自动将第一个and去掉 -->
<where>
<!--
refid:指定 sql片段的id,如果要引用其它命名空间的sql片段,需要前边加namespace

-->
<include refid="query_user_where"/>
</where>
</select>

</mapper>

具体代码示例,看上面两个项目的代码吧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mybatis 框架