MyBatis之三_动态SQL、多表查询、事务管理

一 动态SQL

映射配置文件中可进行SQL语句的动态拼接,需要基于标签:if、where、foreach、sql

  1. where标签相当于SQL语句中的where关键字,进行条件判断;区别是where本身不包含条件判断,需要内部if标签具体条件判断。
  2. if标签进行条件判断,可以接在SQL的where关键字之后,也可以放在where标签内;用if标签主要是为了对where关键字下的多条件判断进行扩展
  3. foreach标签,SQL语句中有些条件涉及容器(如:in),由于MyBatis中传递参数到SQL语句中时没有集合类型,所以需要foreach标签在SQL语句中动态生成集合
    <!-- where 关键字 +  if 标签:where条件保持true,具体条件将if判断-->
    <!-- 注意:if 里面有and,也就是说最后还是字符串拼接-->
    <select id="findUserByCondition" resultType="userMap">
        select * from user where i = 1
        <if test="name != null">
            and username = #{userName}
        </if>
        <if test="id > 10">
            and id = #{id}
        </if>
	</select>

    <!-- where标签 +  if 标签:sql语句更清晰-->
    <!-- 从if里面还是有and来看,似乎只是改由自动生成where 1 = 1了-->
	<select id="findUserByCondition" resultType="userMap">
        select * from user
        <where>
            <if test="name != null">
                and username = #{userName}
            </if>
            <if test="id > 10">
                and id = #{id}
            </if>
        </where>
	</select>


    <!-- foreach标签产生集合:实际还是拼接字符串,open为条件的开始,close为条件的结束-->
    <!-- collection表示实体类中被遍历的集合字段,item表示遍历的每项名称,separator表示item拼接字符串时的分隔符-->
    <!-- #{item的名称} 这个写法表示遍历-->
	<select id="findUserByCondition" resultType="userMap">
        select * from user
        <where>
            <if test="name != null">
                <foreach collection="ids" open="and id in (" close=")" item="name" separator=",">
                    #{name}
                </foreach>
            </if>
        </where>
    </select>

二 多表查询

表间关系:
一对一:一个用户一个身份证号
一对多:一个用户下多个订单
多对一:多个订单属于一个用户
多对多:一个用户有多种角色,一种角色属于多个用户【MySQL中多对多关系的实现是通过两个表都对中间表一对多关系】

MyBatis中的关系:
以上关系是逻辑上的关系,MyBatis实现时只有两种关系:一对一关系、一对多关系;
多对一关系中,将“多”的一方中任意一个记录拿出来,与"一"的一方对应,因为“多”中每次拿一个出来时,就是一对一
多对多关系中,将任意一个“多”中的任意一个记录拿出来,与另一个“多”对应,就是一对多关系

举例:
用户和账号:一个用户可有多个账号,一个账号只属于一个用户
用户和角色:一个用户可有多个角色,一个角色下包含多个用户

实现:

  1. 数据库中关系实现:建立用户表、账户表、角色表、用户角色中间表;账户表外键添加用户表,体现一对多关系;中间表外键分别添加用户表、角色表,实现多对多关系;
  2. Java程序中关系实现:建立用户实体类、账户实体类、角色实体列;一对一关系映射:从表实体中包含一个主表实体的对象引用;一对多关系映射;主表实体应包含从表实体的集合引用
  3. 建立用户配置文件(MyBatis映射配置文件)、账户映射配置文件(MyBatis映射配置文件);
  4. 实现配置:查询用户时,可同时得到用户下的账户信息、角色信息;查询账户时,可同时获取所属用户信息;查询角色时、可获取包含的所有用户信息;

数据表:

user表:id、username

account表:id、uid、money

role表:id、role_name、role_desc

user_role中间表:uid、rid

实体类:

public class User implements Serializable {
    private Integer id;
    private String name;
   	// 用于反映与Account的一对多关系
    private List<Account> accounts;
    // 用于反映与Role的一对多关系
    private List<Role> roles;

    // get、set、toString略
}

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    // 用于反映与User的一对一关系
    private User user;

    // get、set、toString略
}

public class Role implements Serializable {
    private Integer roleId;
    private String roleName;
    private String roleDesc;
    // 用于反映与User的一对多关系
    private List<User> users;
}

接口:

public interface IUserDao{
    public List<User> findUserAccounts();

    public List<User> findUserRoles();
}

public interface IAccountDao {
    // 查询所有账户,并且带有用户信息
    public List<Account> findAllWithUser();
}

public interface IRoleDao {
    public List<Role> findAllWithUser();
}

2.1 XML配置方式

2.1.1 一对一、一对多操作

映射配置文件

IAccountDao.xml 一对一查询

    <!-- 定义封装accout和user的resultMap-->
    <!-- account 类型中有个字段为User应用-->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 一对一关系映射:配置封装user的内容,column属性表明基于主表的哪个字段获取-->
        <!-- javaType属性表明封装对象为什么Java对象-->
        <association property="user" column="uid" javaType="pojo.User">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
        </association>
    </resultMap>

    <!-- 一对一:多表查询-->
    <select id="findAllWithUser" resultType="accountUserMap">
        select a.*,u.username from account a,user a where u.id=a.uid
    </select>


IUserDao.xml 一对多查询

    <!-- 定义User和Account的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <!-- 配置user对象中accounts集合的映射-->
        <collection property="accounts" ofType="account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>

    <select id="findUserAccounts" resultType="userAccountMap">
        select  * from  user u left outer join account a on u.id= a.uid;
    </select>
2.1.2 多对多

多对多要记住:实际是两个表都对中间表进行一对多操作。在Java代码中看不出中间表的存在,但SQL语句基于中间表。

映射配置文件

IRoleDao.xml 一对多查询
    <resultMap id="accountUserMap" type="account">
        <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 property="id" column="id"></id>
            <result property="username" column="username"></result>
        </collection>
    </resultMap>
    <!-- sql语句换行计得要加空格-->
    <select id="findAllWithUser" resultType="accountUserMap">
        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>
    
IUserDao.xml 一对多查询
    <!-- 定义User和Role的resultMap-->
    <resultMap id="userRoleMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <!-- 配置user对象中accounts集合的映射-->
        <collection property="roles" ofType="role">
            <id property="roleId" column="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
    </resultMap>

    <select id="findUserRoles" resultType="userRoleMap">
        select u.* , r.id as rid , r.role_name , r.role_desc from user u
         left outer join user_role ur on u.id = ur.rid
         left outer join user r on r.id = ur.uid;
    </select>

2.2 注解方式

@One:从表(一的一方)

public interface IAccountDao {
    @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"),
            // property:    将返回值注入到 user属性
            // columns:    根据数据表的uid查找user
            // one:        Account与要查找的User是一对一的关系【这里一对一指的是,一个Account只能对应上一个User】
            // select:     多表查询时,要使用的查询方法,指定User中查询方法的全限定方法名
            // FetchType:  多表查询时,延迟加载还是立即加载
            @Result(property = "user",column = "uid",one = @One(
                    select = "IUserDao.findById",
                    fetchType = FetchType.EAGER
            ))
    })
    public List<Account> findAllWithUser();

    @Select("select * from account where uid=#{userId}")
    public Account findByUid(Integer userId);
}

@Many:主表(多的一方)

public interface IUserDao{
    @Select("select * frim user")
    @Results(id = "userMap", value = {
            @Result(id=true,column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(property = "accounts",column = "id",many = @Many(
                    select = "IAccountDao.findByUid",
                    fetchType = FetchType.LAZY
            ))
    })
    public List<User> findUserAccounts();

    public List<User> findUserRoles();
    
    @Select("select * from user where id=#{id}")
    public User findById(Integer id);
}

三 事务管理

什么是事务?
事务的四大特性ACID
不考虑隔离性产生的三个问题
解决办法:四种隔离级别

SqlSession的commit方法进行事务提交,rollback方法进行事务回滚

SqlSessionFactory.openSession(),方法参数默认为false,如果设为true,则SqlSession中的每个方法(Dao接口动态代理底层的方法)操作数据库后会自动提交事务,不需要手动 commit。实际开发中不这么做【如转账操作中,多个对数据库的操作合起来才叫一个事务,要一起commit】。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值