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="[email protected]#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上,有兴趣的可以去看。

原文地址:https://www.cnblogs.com/yangshixiong/p/12247372.html

时间: 2024-10-11 12:42:16

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

mybatis入门篇3 ---- 动态sql,缓存,以及分页jar包的使用

首先我们来看一下动态sql,动态sql就是传递的参数不确定的时候,使用if,where,select,choose,set等标签,先来看一下 lib,rescources,以及utils里面文件不变,直接来看使用 直接看if跟where,if使用比较简单,就是if会有一个条件判断,如果条件满足,就会把if里面的sql语句块加入slq语句,where就是帮助我们加载一个where条件判断,并且会把拼接语句中的第一个and删除掉,接下来看一下例子 看一下UserMapper public inter

Mybatis入门篇

Mybatis 简介: MyBatis 是一款优秀的持久层框架,它支持自定义 SQL.存储过程以及高级映射.MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作.MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型.接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录. 中文文档: https://mybatis.org/mybatis-3/zh/index.html 下载地址: https:

mybatis入门一:mybatis框架原理

一.mybatis框架原理图(图片参考网上) 二.框架原理图解释: 1.mybatis配置 sqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息.mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句.此文件需要在SqlMapConfig.xml中加载 2.通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂 3.由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSessi

mybatis入门篇基——基本配置与参数说明

Mybatis 好吧这是我第一次写这种文章~如果有不足和错误之处欢迎评论,指点.今天想谈谈关于mybatis的一些基础入门知识. 进入正题~~: a.关于mybatis: 我个人觉得mybatis深得中国中庸之道的精髓,虽然在执行速度上来说它没有直接使用jdbc那么效率,也不如Hibernate那么全自动(O/R mapping),只能算是个半自动的(O/R mapping) 但是半自动的好处就在于它的各个方面的缺点也都不像jdbc或者Hibernate那么突出.兼顾了效率也预防了优化sql的问

mybatis入门篇1 --- 编写入门小程序

首先简单说一下为什么使用mybatis,我们上一个项目使用的JDBC,所有的sql语句都是写在java程序中,这样的就会使sql语句与java程序高度耦合,不符合我们的高内聚,低耦合情况,我们只希望你给我一个接口并且返回指定类型的程序,具体如何实现我不管,这样才会更好的进行操作,Hibernate跟mybatis都属于这种情况,hibernate属于全自动框架,mybatis属于半自动框架,什么意思?hibernate对于简单的数据库操作很方便,但是一旦涉及到复杂的数据库操作或者想要对sql语句

Mybatis入门——Spring整合MyBatis

Spring整合MyBatis 对Teacher表进行添加数据和查看数据 1. 创建数据库表 CREATE TABLE `teacher` (  `t_id` varchar(15) NOT NULL,  `t_name` varchar(30) DEFAULT NULL,  PRIMARY KEY (`t_id`)) 2.创建Spring工程 3.导入相关包 mybatis-spring-1.3.0.jar mybatis-3.3.0.jar mysql-connector-java-5.1.

MyBatis入门基础(一)

一:对原生态JDBC问题的总结 新项目要使用mybatis作为持久层框架,由于本人之前一直使用的Hibernate,对mybatis的用法实在欠缺,最近几天计划把mybatis学习一哈,特将学习笔记记录于此,方便大家参考,也方便自己查阅. 话不多说,先看看原始的JDBC程序代码,看看这样的代码存在什么问题. package com.utils; import java.sql.Connection; import java.sql.DriverManager; import java.sql.P

mybatis入门学习之(1)+简单例子测试

Mybatis 入门之(1)环境配置+简单例子测试 什么是MyBatis? 它是支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索.MyBatis 使用简单的XML或注解用于配置和原始映射,将接口和POJOs(Plan Old Java Objects,普通的 Java对象)映射成数据库中的记录. 其实简单一点说mybatis就是一直访问数据库的技术,它是现在比较流行的一个持久层框架,如果你对JDBC熟悉那就更容易

Java框架篇---Mybatis 入门

一.Mybatis介绍 MyBatis是一款一流的支持自定义SQL.存储过程和高级映射的持久化框架.MyBatis几乎消除了所有的JDBC代码,也基本不需要手工去设置参数和获取检索结果.MyBatis能够使用简单的XML格式或者注解进行来配置,能够映射基本数据元素.Map接口和POJOs(普通java对象)到数据库中的记录. 二.MyBatis工作流程 (1)加载配置并初始化 触发条件:加载配置文件 配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个M