简述Mybatis框架(三)

本人小白一枚,欢迎大家一起讨论学习,如有错误,还望大家指教。

简述Mybatis主配置文件中的标签

在这里插入图片描述

  • properties标签 :可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置文件信息。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • typeAliases标签:我们可以采用自定义别名的方式来进行开发,Mybatis默认自定义了很多别名,例如在前面的演示的resultType以及parameterType,当我们的参数或者返回值是String类型时,我们可以直接写类型名称,也可以写包名.类名的方式,如java.lang.String,如下图是Mybatis默认支持的别名。

在这里插入图片描述
在这里插入图片描述

  • mappers标签:该标签用来注册映射配置文件,这里我要强调一下,不同的注册方式,不一定要接口和映射配置文件的路径和名称要一样。
    在这里插入图片描述

简述Mybatis连接池与事务

  • 连接池:在Mybatis的主配置文件中,可以通过<dataSource type="数据源类型">来采用Mybatis自己的连接池技术,当然我们也可以来引用外部的连接池技术。Mybatis自己的数据源分为三类。

    • POOLED:采用传统的javax.sql.DataSource规范中的连接池,Mybatis中有针对规范的实现,我们一般采用这个数据源。
    • UNPOOLED:采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池化技术。
    • JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到DataSource是不一样。 注意:如果不是web或者maven的war工程,是不能使用的。如果使用的是tomcat服务器,采用连接池就是dbcp连接池。
  • 使用外部连接池:我们这里演示使用Druid连接池,只需要两步即可。

    • 1、创建连接池工厂对象(继承PooledDataSourceFactory)。
    • 2、修改配置文件,这里的 property配置需要根据你选择的数据库连接池的具体实现做调整, Druid需要改成下面的配置,同时type写上第一步创建类的全限定类名。
public class DruidDataSourceFactory extends PooledDataSourceFactory {
    public DruidDataSourceFactory() {
        this.dataSource = new DruidDataSource();
    }
}
<dataSource type="data.DruidDataSourceFactory" >
    <property name="driverClass" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
</dataSource>
  • 简述Mybatis事务
    在JDBC中我们可以通过设置setAutoCommit()方法将手动提交事务的方式改为自动提交事务的方式,true表示为自动提交,false为手动提交。Mybatis框架因为是对JDBC的封装,所以Mybatis框架的事务控制方式本身也是用JDBC的setAutoCommit()方法来控制的。我们可以通过SqlSession对象commit方法rollback方法实现事务的提交和回滚,也可以在创建SqlSession对象时,将openSession中的方法设置为true,即session=factory.openSesson(true);

Mybatis的动态SQL语句

在我们实际开发中,如果遇到多条件查询,并且条件是不固定的时候,我们怎么写SQL语句呢?其实Mybatis为我们提供了动态SQL语句。我们可以根据实体类的不同取值,使用不同的SQL语句来进行查询。

  • 动态SQL之<if>标签
    多条件查询用户列表,如果username不为空可以根据username进行查询,如果address不为空还要加入address作为查询条件,表结构及表中记录和工程结构如下,entity包下用来存放实体类,mapper包下用来存放接口,test包下用来测试,这里就不对主配置的内容进行介绍了。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在entity包下创建User实体类,并提供get、set、toString方法。
public class User implements Serializable {
    private int id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    // get/set等方法自行补齐............
}

在mapper包下创建UserMapper接口,并提供根据用户信息进行多条件查询。

public interface UserMapper {
    /**
     * 多条件查询用户列表
     */
    List<User> findByUser(User user);
 }

在resources资源下的mapper下创建UserMapper.xml映射配置文件,并在其添加如下内容。注意,我在主配置文件中将实体类批量注册了别名,所以我这里使用的是别名并批量注册了映射文件,同时在<if>标签的test属性中写的是对象的属性名,这里也是使用的OGNL表达式,另外也要注意where 1 = 1的作用。

<mapper namespace="mapper.UserMapper">
    <select id="findByUser" parameterType="user" resultType="user">
        SELECT * FROM user WHERE 1 = 1
        <if test="username != null and username != ''">
             AND username LIKE "%"#{username}"%"
        </if>
        <if test="address != null and address != ''">
             AND address LIKE "%"#{address}"%"
        </if>
    </select>
</mapper>

在test包下创建测试类,用来测试以上的方法。

@Test
public void findByUserTest() {
    User user = new User();
    user.setUsername("王五");
    user.setAddress("北");
    List<User> users = mapper.findByUser(user);
    users.forEach(item -> System.out.println(item));
}

打印结果
在这里插入图片描述

  • 动态SQL之<where>标签
    上面的<if>标签中,我们需要自己进行where 1=1条件的拼接,为了不手动拼接,我们可以使用<where>标签简化开发。只需要修改上面的映射配置文件,修改如下,并再次进行测试。
<select id="findByUser" parameterType="user" resultType="user">
     SELECT * FROM user
     <where>
         <if test="username != null and username != ''">
             AND username LIKE "%"#{username}"%"
         </if>
         <if test="address != null and address != ''">
             AND address LIKE "%"#{address}"%"
         </if>
     </where>
</select>
@Test
public void findByUserTest() {
    User user = new User();
    user.setAddress("上海");
    List<User> users = mapper.findByUser(user);
    users.forEach(item -> System.out.println(item));
}

在这里插入图片描述

  • 动态SQL之<foreach>标签
    当我们需要传入多个id查询用户信息时用下面两个sql实现:
    SELECT * FROM user WHERE username LIKE '%张%' AND (id =10 OR id =89 OR id=16)
    SELECT FROM user WHERE username LIKE '%张%' AND id IN(10, 89, 16)
    这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来,这样我们就需要<foreach>标签来进行操作了。
    在entity包下创建QueryVo类,并在其添加以下两个属性。
public class QueryVo {
    private List<Integer> ids;
    private User user;
    // get/set等方法自行补齐............
}

在mapper包下的UserMapper接口中添加如下方法。

/**
 * 根据id集合以及用户多条件进行查询
 */
List<User> findByVo(QueryVo vo);

在UserMpper.xml中添加如下内容,因为这里我使用了<sql>标签,目的是将重复的sql进行抽取,使用时引用<include>标签即可,这样可以简便开发。<foreach>标签用于遍历集合,collection:表示要遍历的集合元素。open:表示语句的开始部分,close:表示结束部分,item:表示遍历集合过程中每个元素生成的变量名,sperator:表示分隔符。

<!--抽取重复sql-->
<sql id="defaultUser">SELECT * FROM user</sql>

<select id="findByVo" parameterType="queryVo" resultType="user">
    <include refid="defaultUser"></include>
    <where>
        <if test="user.username != null and user.username != ''">
            AND username LIKE "%"#{user.username}"%"
        </if>
        <if test="ids != null and ids.size() > 0">
            <foreach collection="ids" open=" AND id in (" close=")" item="uid" separator=",">
                #{uid}
            </foreach>
        </if>
    </where>
</select>

测试代码及测试结果

@Test
public void findByVoTest() {
    User user = new User();
    user.setUsername("张");
    QueryVo vo = new QueryVo();
    vo.setUser(user);
    vo.setIds(Arrays.asList(41, 42, 43));
    List<User> users = mapper.findByVo(vo);
    users.forEach(item -> System.out.println(item));
}

在这里插入图片描述

Mybatis多表查询

这里使用简单的用户和账户模型来分析Mybatis多表关系。用户表为user表,即咱们上面使用的那张表,账户表Account表,一个用户(User)可以有多个账户(Account)。具体关系如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 一对一查询
    查询所有账户信息,并关联用户信息。注意:因为一个账户信息只能供给某一个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询,如果从用户信息查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。

方式一:使用resultMap,定义专门的resultMap用于映射一对一的查询结构。在entity下创建Account实体类,并在该实体类下添加一个User类型的属性,用表示该账户是哪个用户的。

public class Account  {
    private int id;
    private int uid;
    private double money;
    private User user;
    // get/set等方法自行补齐............
}

在mapper包下创建一个AccountMapper的接口,并在其中添加一个findAll方法

public interface AccountMapper {
    /**
     * 查询所有账户信息,并包含对应的用户信息。
     * @return
     */
    List<Account> findAll();
}

在resources路径下的mapper包下创建AccountMapper.xml映射配置文件,并在其添加如下内容。

<mapper namespace="mapper.AccountMapper">
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"/>
        <result property="uid" column="uid"/>
        <result property="money" column="money"/>

        <association property="user" javaType="user">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="address" column="address"/>
            <result property="sex" column="sex"/>
            <result property="birthday" column="birthday"/>
        </association>
    </resultMap>
    <select id="findAll" resultMap="accountUserMap">
        SELECT a.id as aid, a.uid,a.money, u.* FROM account a LEFT JOIN `user` u ON u.id = a.uid
    </select>
</mapper>

添加测试代码,并查看测试结果

@Test
public void findAllTest() {
    accountMapper = sqlSession.getMapper(AccountMapper.class);
    List<Account> all = accountMapper.findAll();
    all.forEach(item -> System.out.println(item));
}

在这里插入图片描述
方式二:定义专门的包装类作为输出类型,其中定义了sql查询结果集所有的字段,此方法较为简单,企业中普遍使用这种方法。

public class AccountUser extends User{
    private int aid;
    private int uid;
    private double money;
    // get/set等方法自行补齐............
}

在AccountMapper接口中定义方法

public interface AccountMapper {
    List<AccountUser> findAll();
}

在AccountMapper.xml映射文件中如下内容

<select id="findAll" resultType="accountUser">
    SELECT a.id as aid, a.uid,a.money, u.* FROM account a LEFT JOIN `user` u ON u.id = a.uid
</select>

添加测试代码,并查看结果

 @Test
 public void findByAllTest() {
     accountMapper = sqlSession.getMapper(AccountMapper.class);
     List<AccountUser> all = accountMapper.findAll();
     all.forEach(item -> System.out.println(item));
 }

在这里插入图片描述

  • 一对多查询
    查询所有用户信息及其对应的额账户信息。用户信息和账户信息为一对多的关系,并且查询过程中如果用户没有账户信息,我们也要将此记录查询出来,这里也就是使用左连接。

在entity包下的User类中添加accounts属性。

public class User {
    private int id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<Account> accounts;
    // get/set等方法自行补齐............
}

在mapper包下中的UserMapper添加如下方法

 /**
  * 查询用户信息,并查询对应的账户信息
  */
 List<User> findAll();

在UserMapper.xml映射配置文件添加如下内容,collection表示一对多的关系,preperty表示关联查询的结果集存储在实体类的哪个属性上,ofType表示指定关联查询的结果集中的对象类型为什么类型,即List中对象类型,此处可以使用别名,也可以使用全限定名。

<resultMap id="userAccountMap" type="user">
     <id column="id" property="id"/>
     <result column="address" property="address"/>
     <result column="username" property="username"/>
     <result column="sex" property="sex"/>
     <result column="birthday" property="birthday"/>
     
     <!-- collection 是用于建立一对多中集合属性的对应关系    ofType 用于指定集合元素的数据类型    --> 
     <collection property="accounts" ofType="account">
         <id column="aid" property="id"/>
         <result column="uid" property="uid"/>
         <result column="money" property="money"/>
     </collection>
</resultMap>
<select id="findAll" resultMap="userAccountMap">
    SELECT u.*, a.id as aid, a.money, a.uid FROM `user` u LEFT JOIN account a ON u.id = a.uid
</select>

添加测试方法,并查看测试结果

 @Test
 public void findAllTest() {
     accountMapper = sqlSession.getMapper(AccountMapper.class);
     List<AccountUser> all = accountMapper.findAll();
     all.forEach(item -> System.out.println(item));
 }

在这里插入图片描述

  • 多对多查询
    前面我们学习了使用Mybatis实现一对多关系的维护,多对多关系可以看成是双向的一对多关系。这里使用用户与角色的关系模型,即一个用户可以拥有多种角色,一个角色同样可以被多个用户使用。
    在这里插入图片描述
    向数据库中添加角色表以及用户角色的中间表,并向表中添加如下记录。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    查询所有角色并关联查询对应的用户信息。在entity包下创建role实体类。
public class Role {
    private int roleId;
    private String roleName;
    private String roleDesc;
    private List<User> users;
    // get/set等方法自行补齐............
 }

在mapper包下创建RoleMapper接口,并添加findAll方法。

public interface RoleMapper {
    /**
     * 查询所有角色信息,并查询出对应关联的用户信息
     */
    List<Role> findAll();
}

在resources资源路径下的mapper包中创建RoleMapper.xml映射配置文件

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.RoleMapper">
    <resultMap id="roleUserMap" type="role">
        <id property="roleId" column="rid"/>
        <result property="roleName" column="role_name"/>
        <result property="roleDesc" column="role_desc"/>
        <collection property="users" ofType="user">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
        </collection>
    </resultMap>

    <select id="findAll" resultMap="roleUserMap">
        SELECT r.id as rid, r.role_name, r.role_desc, u.* FROM role r INNER JOIN user_role ur ON ur.rid = r.id INNER JOIN `user` u ON u.id = ur.uid
    </select>
</mapper>

编写测试代码并查看测试结果,图片过于长,这里分两张进行展示

@Test
public void findByAllRoleTest() {
    roleMapper = sqlSession.getMapper(RoleMapper.class);
    List<Role> roles = roleMapper.findAll();
    roles.forEach(item -> System.out.println(item));
}

在这里插入图片描述在这里插入图片描述
从User出发,我们也可以发现一个用户可以具有多个角色,这样用户到角色的关系也还是一个一对多的关系,这样我们就可以将user与role的多对多关系拆解成一对多的关系来实现。这里就不展示用户到角色的一对多的查询了。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值