mybatis入门篇2 --- mybatis的部分配置信息以及连表查询,分步查询

接下来看一下我们的mybatis的进一步操作,熟悉一下相关配置信息,以及多参数查询,连表查询,以及分布查询的功能。

首先mybatis的中文文档就是:https://mybatis.org/mybatis-3/zh/configuration.html#environments

首先看一下三个数据库表,user,order,user_order,这是一个多对多关系。

userId对应user表的id, orderId对应order表的id

本次对于user表没有记性一对多的操作,仅查询user表信息,对于order操作进行操作一对多关系。多对多就是分别的一对多

 

 

 

 

 

 

 

 

首先看一下项目结构,lib包里面的jar包不变

utils里面的类跟之前一样,不再展示。

 看一下我们的db.properties,这个就是指定我们的数据库连接信息,

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=mysql 

 接下来看一下我们配置信息,如果其他信息,可以到上面的文档中继续查找

<?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>
    <!--
    MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下
    properties(属性)
    settings(设置)
    typeAliases(类型别名)
    typeHandlers(类型处理器)
    objectFactory(对象工厂)
    plugins(插件)
    environments(环境配置)
    environment(环境变量)
    transactionManager(事务管理器)
    dataSource(数据源)
    databaseIdProvider(数据库厂商标识)
    mappers(映射器)
    -->
    <!--定义属性以及读取属性文件-->
    <properties resource="db.properties" />
    <!--这个就是初始化配置-->
    <settings>
        <!--配置sql打印,将sql打印到控制台-->
        <setting name="logImpl"  value="STDOUT_LOGGING"/>
        <!--开启驼峰命名法,默认是false,一旦开启true,那么必须符合所有的驼峰体与数据链蛇形字体的对应,否则无法进行赋值-->
        <setting name="mapUnderscoreToCamelCase" value="false"/>
        <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。就是我们当时的那个collection里面,如果不进行调用user,那么就不会打印信息-->
        <setting name="lazyLoadingEnabled" value="true"/>

        <!--当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载-->
        <setting name="aggressiveLazyLoading" value="false"/>

        <!--指定哪个对象的方法触发一次延迟加载。-->
        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>

    </settings>

    <!--定义别名-->
    <typeAliases>
        <!--单个别名的定义-->
<!--        <typeAlias alias="User" type="com.yang.domain.User" />-->
        <!--批量定义别名,别名就是定义的类名-->
        <package name="com.yang.domain" />
    </typeAliases>

    <!--
    这个就是配置换奖,其中default可以指定选择哪个环境,这个也可以在创建连接工厂时指定
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
    -->
    <environments default="development">
        <!--这个是开发环境配置-->
        <environment id="development">
            <!--使用事务-->
            <transactionManager type="JDBC" />
            <!--
            这个指定数据库源,
            pooled这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的流行处理方式。,
            UNPOOLED这个数据源的实现只是每次被请求时打开和关闭连接, 不同的数据库在性能方面的表现也是不一样的,对于某些数据库来说,使用连接池并不重要,
            -->
            <!--从文件加载的数据库配置-->
            <dataSource type="POOLED">
                <!--这是 JDBC 驱动的 Java 类的完全限定名(并不是 JDBC 驱动中可能包含的数据源类-->
                <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>
            <!--写死的数据库配置-->
<!--            <dataSource type="UNPOOLED">-->
<!--                &lt;!&ndash;这是 JDBC 驱动的 Java 类的完全限定名(并不是 JDBC 驱动中可能包含的数据源类&ndash;&gt;-->
<!--                <property name="driver" value="com.mysql.jdbc.Driver" />-->
<!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />-->
<!--                <property name="username" value="root" />-->
<!--                <property name="password" value="mysql" />-->
<!--            </dataSource>-->
        </environment>
        <!--这个是上线环境配置-->
        <environment id="prod">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="!@#QAZwsx" />
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <!--这个是之前使用的定义单个文件映射-->
<!--        <mapper resource="com/yang/domain/Customer.xml" />-->
        <!--现在使用包结构定义映射文件,需要遵从下面规范
        1。名称必须要跟接口名称一致
        2。必须和mapper接口在同一个目录
        -->
        <package name="com.yang.mapper" />
    </mappers>
</configuration>

看一下javabean

// user
public class User {
    private Integer id;
    private String username;
    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

// order
public class Order {
    private Integer id;
    private String name;
    private List<User> users = new ArrayList<>();

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", users=" + users +
                '}';
    }
}

接下来,我们看一下mapper的编写,首先看一下基本规范

  1. namespace必须和Mapper接口类路径一致
  2. id必须和Mapper接口方法名一致
  3. parameterType必须和接口方法参数类型一致
  4. resultType必须和接口方法返回值类型一致

我们看一下UserMapper,就是一个接口类,我们使用debug看源码时,发现有使用invoke这个方法,并且jar包有cglib,这就是反射来帮助我们进行处理的,记住多参数传值必须指定param的值,否则就需要按顺序使用param1,param2.。。。

package com.yang.mapper;

import com.yang.domain.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    /*
    mapper接口编写规则:
    1.namespace必须和Mapper接口类路径一致
    2.id必须和Mapper接口方法名一致
    3.parameterType必须和接口方法参数类型一致
    4.resultType必须和接口方法返回值类型一致
    **/

    // 通过指定的ID来获取user对象
    User getUserById(Integer id);

    // 获取全部用户
    List<User> getUsers();

    // 新建用户
    void insertUser(User user);

    // 删除用户,可以通过指定param的value来确定xml文件中使用的参数名称
    void deleteUser(@Param("id") Integer id);

    // 将类按照map格式返回
    Map<String, Object> getUserMapById(@Param("id") Integer id);

    // 多参数传递
    User getUserByArgs(@Param("id") Integer id, @Param("username") String username);

    // 结果集使用resultMap
    User getResultMapById(@Param("id") Integer id);

    // 根据用户订单关系获取用户
    User getUserThoughRelation(@Param("orderId") Integer orderId);

}

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">
<!--这个namespace必须与映射的类接口一致-->
<mapper namespace="com.yang.mapper.UserMapper">

    <!--因为我们之前配置了别名,所以可以直接使用User来代替com.yang.domain.User-->
    <select id="getUserById" resultType="User">
        select * from `user` where id = #{id}
    </select>
    <!--获取全部用户-->
    <select id="getUsers" resultType="com.yang.domain.User">
        select * from `user`;
    </select>


    <!--
    useGeneratedKeys="true" keyProperty="id" keyColumn="id" 这是另一种方法获取id值
    这个跟之前写的是一样的
        <selectKey keyColumn="id" keyProperty="id" resultType="Integer" order="AFTER">
            select last_insert_id()
        </selectKey>
    -->
    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        insert into `user` (username, password) values (#{username}, #{password});
    </insert>

    <!--parameterType这个可以不用声明-->
    <delete id="deleteUser">
--         delete from `user` where id=${id}
        delete from `user` where id=#{id}
    </delete>

    <!--第一种传参方法,这个不安全,容易被sql注入-->
    <!--==>  Preparing: select * from `user` where id=2 -->
    <select id="getUserMapById" resultType="java.util.Map">
       select * from `user` where id=${id}
   </select>


    <!--第二种查询方法,这种可以放置sql注意,可以看出这个使用占位符插入数据-->
    <!--==>  Preparing: select * from `user` where id=? -->
<!--    <select id="getUserMapById" resultType="java.util.Map">-->
<!--        select * from `user` where id=#{id}   -->
<!--    </select>-->

    <!--这个就是传递多参数,必须使用我们当时定义的那个-->
    <select id="getUserByArgs" resultType="com.yang.domain.User">
        select * from `user` where id=#{id} and username=#{username}
    </select>

    <resultMap id="userMap" type="User">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="password" property="password" />
    </resultMap>
    <!--使用resultMap指定乐行,column代表数据库字段,property代表java类字段-->
    <select id="getResultMapById" resultMap="userMap">
        select * from `user` where id=#{id}
    </select>
    <!--根据用户订单关系表获取用户-->
    <select id="getUserThoughRelation" resultType="com.yang.domain.User">
        select * from `user` where id in(select userId from `user_order` where orderId = #{orderId})
    </select>
</mapper>

接下来,我们需要看一下一对多查询,一对多查询我们可以使用一条sql语句连表查询出来,并且封装一个resultMap来进行赋值结果,或者使用分布查询,来实现,建议使用分步查询,尽量少使用连表查询

OrderMapper

package com.yang.mapper;

import com.yang.domain.Order;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface OrderMapper {
    // 插入一条order
    void insertOrder(Order order);

    // 插入关系表
    void insertRelation(@Param("userId") Integer userId, @Param("orderID") Integer orderId);

    // 获取所有订单
    List<Order> getAllOrder();

    // 获取单个订单
    Order getOrderById(Integer id);
}

OrderMapper.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">
<!--这个namespace必须与映射的类接口一致-->
<mapper namespace="com.yang.mapper.OrderMapper">

    <!--插入订单信息,并返回id-->
    <insert id="insertOrder" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into `order`(name) values (#{name})
    </insert>
    <!--插入关系表-->
    <insert id="insertRelation">
        insert into `user_order`(userId, orderId) values (#{userId}, #{orderID})
    </insert>


    <resultMap id="ordersMap" type="Order">
        <!--这个是指定字段, 对于主键可以使用id或者result,其他字段只能使用resule-->
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <!--这个字段对应的是用户列表。因此使用collection进行赋值,指定type是list,里面的字段是User类型,然后在里面在指定赋值字段-->
        <collection property="users" javaType="list" ofType="User">
            <id column="userId" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
        </collection>
    </resultMap>
    <!--通过连表查询查处所有数据-->
    <select id="getAllOrder" resultMap="ordersMap">
        select * from `order` as o
        left join `user_order` as uo on o.id = uo.orderId
        left join `user` as u on uo.userId = u.id
    </select>


    <resultMap id="orderMap" type="Order">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <collection property="users" javaType="list" ofType="Order"
                    select="com.yang.mapper.UserMapper.getUserThoughRelation"
                    column="id"
        />

    </resultMap>
    <!--分布查询-->
    <select id="getOrderById" resultMap="orderMap">
        select * from `order` where id = #{id}
    </select>


</mapper>

接下来看一下我们的测试

package com.yang.test;

import com.yang.domain.Order;
import com.yang.domain.User;
import com.yang.mapper.OrderMapper;
import com.yang.mapper.UserMapper;
import com.yang.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;
import java.util.Map;

public class MyTest {
    @Test
    public void getUser() {
        // 建立sql连接会话
        SqlSession sqlSession = MyBatisUtils.openSession();
        // 获取用户映射
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 通过定义的接口进行查询数据库
        User user = userMapper.getUserById(1);
        System.out.println(user);  // User{id=1, username='yang', password='1234'}

        List<User> users = userMapper.getUsers();
        for (User user1 : users) {
            System.out.println(user1);
            /*
                User{id=1, username='yang', password='1234'}
                User{id=2, username='shi', password='5678'}
                User{id=3, username='xiong', password='9012'}
             */
        }
        // 增加用户
        User newUser = new User();
        newUser.setUsername("mark");
        newUser.setPassword("1111");
        userMapper.insertUser(newUser);
        System.out.println(newUser);  // User{id=7, username='mark', password='1111'}
        sqlSession.commit();

        // 删除用户
        userMapper.deleteUser(8);
        sqlSession.commit();
        // 关闭连接
        sqlSession.close();
    }

    @Test
    public void getUserMap() {
        // 建立sql连接会话
        SqlSession sqlSession = MyBatisUtils.openSession();
        // 获取用户映射
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 通过定义的接口进行查询数据库
        Map<String, Object> user = userMapper.getUserMapById(2);
        System.out.println(user);  // {password=5678, id=2, username=shi}
        // 关闭连接
        sqlSession.close();
    }

    @Test
    public void getUseByArgs() {
        // 建立sql连接会话
        SqlSession sqlSession = MyBatisUtils.openSession();
        // 获取用户映射
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 通过定义的接口进行查询数据库
        User user = userMapper.getUserByArgs(2, "shi");
        System.out.println(user);  // User{id=2, username='shi', password='5678'}
        // 关闭连接
        sqlSession.close();
    }

    @Test
    public void getResultMap() {
        // 建立sql连接会话
        SqlSession sqlSession = MyBatisUtils.openSession();
        // 获取用户映射
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.getResultMapById(2);
        System.out.println(user); // User{id=2, username='shi', password='5678'}
        sqlSession.close();
    }

    @Test
    public void orders() {
        // 建立sql连接会话
        SqlSession sqlSession = MyBatisUtils.openSession();
        // 获取用户映射
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        // 获取订单映射
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        User user = userMapper.getUserById(3);
        Order order = new Order();
        order.setName("订单三");
        order.getUsers().add(user);
        // 添加订单
        orderMapper.insertOrder(order);
        // 添加关系映射
        orderMapper.insertRelation(user.getId(), order.getId());
        // 提交事务
        sqlSession.commit();
        // 查询所有的订单
        List<Order> allOrder = orderMapper.getAllOrder();
        for (Order order1 : allOrder) {
            System.out.println(order1);
            /*
                Order{id=3, name='订单三', users=[User{id=2, username='shi', password='5678'}, User{id=6, username='mark', password='1111'}]}
                Order{id=4, name='订单三', users=[User{id=3, username='xiong', password='9012'}, User{id=2, username='shi', password='5678'}]}
                Order{id=5, name='订单三', users=[User{id=3, username='xiong', password='9012'}]}
                Order{id=6, name='订单三', users=[User{id=3, username='xiong', password='9012'}]}
                Order{id=1, name='订单一', users=[]}
                Order{id=2, name='订单二', users=[]}
             */
        }
        sqlSession.close();
    }

    @Test
    public void order() {
        // 建立sql连接会话
        SqlSession sqlSession = MyBatisUtils.openSession();
        // 获取订单映射
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        // 通过分步查询获取订单
        Order order = orderMapper.getOrderById(2);
        System.out.println(order);  // Order{id=3, name='订单三', users=[User{id=2, username='shi', password='5678'}, User{id=6, username='mark', password='1111'}]}
        System.out.println(order);
        sqlSession.close();
    }

}

源码地址都是前面提到的GitHub上,有兴趣的可以去看。

 

posted @ 2020-02-01 00:28  灬灬灬灬灬灬  阅读(317)  评论(0编辑  收藏  举报