MyBatis

Myatis的使用执行流程:

1.创建SqlMapConfig.xml配置文件,配置连接数据库的参数信息和mapper的映射对象

2.SqlSessionFactoryBuilder读取SqlMapConfig.xml文件流,构建出SqlSessionFactory对象

3.SqlSessionFactory读取SqlMapConfig.xml中的信息产生真正操作数据库的SqlSession对象

4.SqlSession利用getMapper(ClassType)用来生成代理接口对象,定义通用的增删改查方法,还可以对事务进行提交,回滚,关闭资源等操作

5.注解和xml的开发方式示例:

注解:
@Select("select * from user")
public List<User> findAll();
xml:
<mapper namespace="com.haha.dao.UserDao">
    <select id="findAll" resultType="user">
        select * from user
    </select>
    <select id="findById" parameterType="java.lang.Integer" resultType="com.haha.domain.User">
        select * from  user where id=#{uid};
    </select>
</mapper>

1.基于代理 Dao 实现 CRUD 操作

查询操作:

<!-- 根据 id 查询 -->
<select id="findById" resultType="com.haha.domain.User" parameterType="int">
    select * from user where id = #{uid}
</select>
细节:

resultType 属性:用于指定结果集的类型。
parameterType 属性:用于指定传入参数的类型。
sql 语句中使用#{}字符:它代表占位符, 相当于原来 jdbc 部分所学的'?',都是用于执行语句时替换实际的数据,具体的数据是由#{}里面的内容决定的。

保存操作:

<!-- 保存用户-->
<insert id="saveUser" parameterType="com.haha.domain.User">
    insert into user(username,birthday,sex,address)
    values(#{username},#{birthday},#{sex},#{address})
</insert>

<!-- 保存用户并返回用户的id-->
<insert id="saveUser" parameterType="USER">
    <!-- 配置保存时获取插入的 id -->
    <selectKey keyColumn="id" keyProperty="id" resultType="int">
        select last_insert_id();
    </selectKey>
    insert into user(username,birthday,sex,address)
    values(#{username},#{birthday},#{sex},#{address})
</insert>

更新操作:

<update id="updateUser" parameterType="com.haha.domain.User">
    update user set username=#{username},birthday=#{birthday},sex=#{sex},
    address=#{address} where id=#{id}
</update>

删除操作:

<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{uid}
</delete>

模糊查询:

使用concat()进行字符拼接法:
List<User> findUser(@Param("name") String name);

<select id="findUser" resultType="com.haha.domain.User" parameterType="String">
    select * from user where name like concat('%',#{name},'%')        
</select>
事先在代码中将各个参数拼接好"%",然后在dao层指定各个参数的别名方法:
List<USer> findUser(@Param("name") String name,@Param("address") String address);

<select id="findUser" resultType="com.haha.domain.User" parameterType="String">
    select * from user where name like #{name} or address like #{address}
</select>

聚合函数查询:

<select id="findTotal" resultType="int">
    select count(*) from user;
</select>

resultMap 结果类型:

resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类 型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。

1.定义resultMap:

<resultMap type="com.haha.domain.User" id="userMap">
    <id column="id" property="userId"/>
    <result column="username" property="userName"/>
    <result column="sex" property="userSex"/>
    <result column="address" property="userAddress"/>
    <result column="birthday" property="userBirthday"/>
</resultMap>
属性介绍:

type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称

标签介绍:

id标签:用于指定主键字段
result 标签:用于指定非主键字段

2.引用resultMap:

<select id="findAll" resultMap="userMap">
select * from user
</select>

动态sql

1.<if>标签:

<select id="findByUser" resultType="user" parameterType="user">
    select * from user where 1=1
    <if test="username!=null and username != '' ">
        and username like concat('%',#{username},'%')
    </if>
    <if test="address != null">
        and address like concat('%',#{address},'%')
    </if>
</select>

<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL(写法样式:user.username,user.address等) 表达式的写法。

2.<include>标签:引用创建好的sql语句

创建sql语句:
<sql id="defaultUser">
        select * from user
</sql>
引用:
<select id="findByName" resultMap="userMap">
    <include refid="defaultUser"></include>
</select>

3.<foreach>标签:

<select id="findInIds" resultType="com.haha.domain.User" parameterType="List">
    <!--引用 select * from user 语句-->
    <include refid="defaultUser"></include>   
    <where>
        <if test="ids != null and ids.size() > 0">
            <foreach collection="ids" open="id in ( "  close=")"  item="uid" separator="," >
                #{uid}
            </foreach>
        </if>
    </where>
</select>

SQL 语句:select 字段 from user where id in (?)
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符

多表查询

one对many:

例如一个用户有多个账户,一个账户只能对应一个用户,
则user实体类中含有private List<Account> accounts属性,
account实体类中含有private User user属性

1.多对一:查询账户中的信息包含该账户的的用户信息操作
调用user的findById方法查询:
<resultMap type="account" id="accountMap">
    <id column="aid" property="id"/>
    <result column="uid" property="uid"/>
    <result column="money" property="money"/>
    <!-- 它是用于指定从表方的引用实体属性的 -->
    <association property="user" column="uid" javaType="user" select="com.haha.dao.UserDao.findById">
        <id property="ID" column="aid"></id>
        <result property="UID" column="uid"></result>
        <result property="MONEY" column="money"></result>   
    </association>
</resultMap>

<select id="findAll" resultMap="accountMap">
select * from account
</select>

前提是接口UserDao中有findById(uid)这个方法
select: 填写我们要调用的 select 映射的 id
column : 填写我们要传递给 select 映射的参数

不调用方法,使用外联查询:
<resultMap id="accountUserMap" type="com.haha.domain.Account">
    <id property="ID" column="aid"></id>
    <result property="UID" column="uid"></result>
    <result property="MONEY" column="money"></result>
    <association property="user" column="uid" javaType="com.haha.domain.User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
    </association>
</resultMap>

<!--引用映射-->
<select id="findAll" resultMap="accountMap">
    select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
</select>

association:用于many对one时,关联"one"的结果集
column:用于指定根据对象的哪个属性来查找结果集。
javaType:封装的类型

2.一对多:查询所有用户信息及用户关联的账户信息
调用account的findById方法查询封装accounts:
<resultMap id="userAccount" type="com.haha.domain.User">
    <id property="id" column="id"></id>
    <result property="username" column="username"></result>
    <result property="birthday" column="birthday"></result>
    <result property="sex" column="sex"></result>
    <result property="address" column="address"></result>
    <collection property="accounts" column="id" ofType="com.haha.domain.Account" select="com.haha.dao.IAccountDao.findById">
        <id property="ID" column="aid"></id>
        <result property="UID" column="uid"></result>
        <result property="MONEY" column="money"></result>
    </collection>
</resultMap>

<select id="findAll" resultMap="userAccount">
    select * from user
</select>

ofType 用于指定集合元素的数据类型
select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称)
column 是用于指定使用哪个字段的值作为条件查询

不调用方法:
    <!--建立对应关系-->
<resultMap id="userAccount" type="com.haha.domain.User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <collection property="accounts" ofType="com.haha.domain.Account">
            <id property="ID" column="aid"></id>
            <result property="UID" column="uid"></result>
            <result property="MONEY" column="money"></result>
        </collection>
    </resultMap>
    
    <!--引用映射-->
    <select id="findAll" resultMap="userAccount">
    select u.*,a.id as aid ,a.uid,a.money from user u left outer join account a on u.id =a.uid
    </select>

collection:用于one对many时,关联"many"的结果集
结果集中的属性:
property:关联查询的结果集存储在对象中的哪个属性上。
ofType:指定关联查询的结果集中的对象类型即 List中的对象类型。此处可以使用别名,也可以使用全限定名。

many对many:

例如一个用户对应多个角色,一个角色对应多个用户,
则user实体类中含有private List<Role> Roles属性,
role实体类中含有private List<User> Users属性

查询角色信息,并且展示角色中的用户信息:
<resultMap id="roleMap" type="role">
    <id property="roleId" column="rid"></id>
    <result property="roleName" column="role_name"></result>
    <result property="roleDesc" column="role_desc"></result>
    <collection property="users" ofType="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="address" property="address"></result>
        <result column="sex" property="sex"></result>
        <result column="birthday" property="birthday"></result>
    </collection>
</resultMap>

<select id="findAll" resultMap="roleMap">
    select u.*,r.id as rid,r.role_name,r.role_desc from role r
    left outer join user_role ur on r.id = ur.rid
    left outer join user u on u.id = ur.uid
</select>

MyBatis的注解开发

常用注解:

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用

查询所有用户:
@Select("select * from user")
@Results(id="userMap",value= {
    @Result(id=true,column="id",property="userId"),
    @Result(column="username",property="userName"),
    @Result(column="sex",property="userSex"),
    @Result(column="address",property="userAddress"),
    @Result(column="birthday",property="userBirthday")
})
List<User> findAll();

如果实体类中的属性名和数据库中的列名一一对应,可以省略@Results注解

根据id查询用户:
@Select("select * from user where id = #{uid} ")
@ResultMap("userMap")
User findById(Integer userId);
保存(添加)用户:
@Insert("insert into user(username,sex,birthday,address)values(#{username},#{sex},#{birthday},#{address})")
void saveUser(User user);
保存(添加)用户并返回新增用户的id值:
@Insert("insert into user(username,sex,birthday,address)values(#{username},#{sex},#{birthday},#{address})")
@SelectKey(keyColumn="id",keyProperty="id",resultType=Integer.class,before =false, statement = { "select last_insert_id()" })
int saveUser(User user);
更改用户数据:
@Update("update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id} ")
void updateUser(User user);
根据用户id删除用户:
@Delete("delete from user where id = #{uid} ")
void deleteUser(Integer userId);
使用聚合函数:
@Select("select count(*) from user ")
void findTotal();
模糊查询:
@Select("select * from user where username like concat('%',#{username},'%') ")
List<User> findByName(String name);

使用注解实现复杂关系映射开发

在使用注解开发时我们需要借助 @Results 注解, @Result 注解, @One 注解, @Many 注解。

@Resutl 注解代替了 <id>标签和<result>标签

属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))

@One 注解(一对一)

代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。

@Many 注解(多对一)

代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,
属性的 javaType(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))

查询所有账户信息包括账户中的user信息并使用延迟加载:
@Select("select * from account")
@Results({
    @Result(id=true,column="id",property="id"),
    @Result(column="uid",property="uid"),
    @Result(column="money",property="money"),
    @Result(column="uid",property="user",one=@One(select="com.haha.dao.IUserDao.findById",fetchType=FetchType.LAZY))
})
List<Account> findAll();
如果将来要对@Results进行引用应用,@Results中的需要添加id和value标签:
@Select("select * from account")
@Results(id="accountMap",
    value= {
    @Result(id=true,column="id",property="id"),
    @Result(column="uid",property="uid"),
    @Result(column="money",property="money"),
    @Result(column="uid",property="user",one=@One(select="com.haha.dao.IUserDao.findById",fetchType=FetchType.LAZY))
})
List<Account> findAll();

@Select("select * from account where aid = #{aid} ")
@ResultMap("accountMap")
Account findById(Integer accountId);
查询所有用户信息包括用户中的账户信息并使用延迟加载:
@Select("select * from user")
@Results({
    @Result(id=true,column="id",property="userId"),
    @Result(column="username",property="userName"),
    @Result(column="sex",property="userSex"),
    @Result(column="address",property="userAddress"),
    @Result(column="birthday",property="userBirthday"),
    @Result(column="id",property="accounts",many=@Many(select="com.haha.dao.IAccountDao.findByUid",fetchType=FetchType.LAZY))
    })
List<User> findAll();

MyBatis的缓存:

一级缓存

一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。当调用 SqlSession 的修改,添加,删除, commit(),
close()等方法时,就会清空一级缓存。

二级缓存

二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,
多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

在 SqlMapConfig 中开启二级缓存支持:
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
使用二级缓存
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}

因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。
当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化
方式来保存对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容