当前位置: 首页 > news >正文

Mybatis笔记(上)

mybatis简介

什么是MyBatis?

简化数据库操作的,但在这框架下我们还是要写sql语句的

Mybatis是一个持久层框架,用于简化数据库操作。它通过sql或者注解将Java对象与SQL语句映射,避免了手动设置参数和结果集处理的繁琐工作。

Mybatis简化了数据库操作,提供了灵活的SQL控制,适合需要精细管理sql的项目

核心特点:

①SQL映射

②简化数据库操作

③灵活性

④集成方便

基本实现

     使用MyBatis的步骤:

     1导入依赖

     2准备实体类

     3创建一个mapper接口,mapperxml文件

     4准备mybatis的配置文件(连接数据库信息,mapper.xml位置)

     5使用mybatis进行数据库的查询

代码举例:

Mapper接口

/**

 * 规定数据库方法即可

 */

public interface EmployeeMapper {

    //根据id查询员工信息

    Employee queryById(Integer id);

    //根据id删除员工

    int deleteById(Integer id);

}

写在EmployeeMapper.xml文件中的

     声明标签写sql语句 crud select insert update delete

     每个标签对应接口的一个方法!方法的一个实现!

     只有查询才有返回值:   id=每个方法的名字   resultType=每个方法的返回结果

     注意;Mapper接口中的方法不能重载,因为xml文件不能映射,xml是根据方法名识别的!

    <select id="queryById" resultType="org.example.pojo.Employee">

        <!-- #{empId}代表动态传入的参数,并且进行赋值!后面详细讲解 -->

        select emp_id empId,emp_name empName, emp_salary empSalary from

        t_emp where emp_id = #{empId}

    </select>

    <delete id="deleteById">

        delete from t_emp where emp_id=#{id}

    </delete>

Mybatis-config.xml文件

<?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>

    <settings>
        <!-- 开启了 mybatis的日志输出,选择使用system进行控制台输出 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!-- environments表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
    <environments default="development">
        <!-- environment表示配置Mybatis的一个具体的环境 -->
        <environment id="development">

            <!-- Mybatis的内置的事务管理器
             MANAGED 不会自动开启事务!
             JDBC 自动开启事务,需要自己提交事务!(常用)
             -->
            <transactionManager type="JDBC"/>

            <!-- 配置数据源 (一般我们会使用Druid连接池,不使用mybatis的)
              POOLED mybatis帮助我们维护一个连接池
              UNPOOlED 每次都新建或者释放连接
            -->
            <dataSource type="POOLED">
                <!-- 建立数据库连接的具体信息 -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis-example"/>
                <property name="username" value="root"/>
                <property name="password" value="abc123LQ"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
        <!-- mapper标签:配置一个具体的Mapper映射文件 -->
        <!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
        <!--    对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
        <mapper resource="mappers/EmployeeMapper.xml"/>
    </mappers>

</configuration>

测试类:

public class MyBatisTest {

    /**

     * mybatis提供的api进行方法的调用

     * 1 读取外部配置文件(mybatis-config.xml)

     * 通过Resources 调用 getResourceAsStream()方法传入"mybatis-config.xml"-------获得一个输入流对象

     *

     * 2 创建sqlSessionFactory

     * 通过new一个SqlSessionFactoryBuilder(),再调用build()方法,传入上面创建的输入流对象--------获得sqlSessionFactory对象

     *

     * 3 根据sqlSessionFactory创建sqlSession(每次业务创建一个,用完就释放)

     * 通过上面创建的sqlSessionFactory对象调用openSession()方法-----------------拿到sqlSession对象

     *

     * 4 获取接口的代理对象(代理技术)调用代理对象的方法,就会查找mapper接口的方法

     * 通过上面创建的sqlSession对象调用getMapper()方法传入EmployeeMapper.class(规定方法的的接口)--------得到一个代理对象

     * 通过代理对象我们就可以调用接口中的方法,代理对象会自动找到对应的sql语句执行

     *

     * 5 提交事务(非DQL)和释放资源(对于sqlSession来说的)

     */

    @Test

    public void test1() throws IOException {

        //1 读取外部配置文件(mybatis-config.xml)

        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");



        //2 创建sqlSessionFactory

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);



        //3 根据sqlSessionFactory创建sqlSession(每次业务创建一个,用完就释放)

        SqlSession sqlSession = sqlSessionFactory.openSession();



        //4 获取接口的代理对象(代理技术)调用代理对象的方法,就会查找mapper接口的方法

      //jdk动态代理技术生成的mapper代理对象

        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

       //内部拼接接口的全限定符号.方法名  去查找sql语句标签

     //1 拼接 类的权限限定符.方法名  整合参数 -》ibatis对应的方法传入参数

     //mybatis底层依然调用ibatis只不过有固定的模式!

        Employee employee = mapper.queryById(1);

        System.out.println(employee);

        //5 提交事务(非DQL)和释放资源

        sqlSession.commit();

        sqlSession.close();

    }

}

日志输出设置

在mybatis-config.xml文件的setting标签中设置:

        <!-- 开启了 mybatis的日志输出,选择使用system进行控制台输出 -->

        <setting name="logImpl" value="STDOUT_LOGGING"/>

取值符#与$区别 

    #$取值符号的区别

    #{key}:占位符+赋值 emp_id=? -> ?=赋值

    ${key}:字符串拼接  "emp_id=" + id ->最终形成了一个sql语句

    推荐使用#{key}防止出现注入攻击问题

    特殊情况:

    ?只能替代值的位置,不能替代容器名(标签,列名,sql关键字)emp_id = ? 不能写成 ?=

    但是如果遇到列名也是需要用户传入的时候,就需要使用${key}

    例如

        sql select * from 表 where 列名是动态的${columnName} = 动态的值 #{columnValue}

    总结:动态值 使用#{key} ; 动态列名 容器名 关键字 使用${key}

传值问题:

简单类型传入(单个值)

概念说明:

这里数据输入具体是指上层方法(例如Service方法)调用Mapper接口时,数据传入的形式。

- 简单类型:只包含一个值的数据类型

    - 基本数据类型:int、byte、short、double、……

    - 基本数据类型的包装类型:Integer、Character、Double、……

    - 字符串类型:String

- 复杂类型:包含多个值的数据类型

    - 实体类类型:Employee、Department、……

    - 集合类型:List、Set、Map、……

    - 数组类型:int[]、String[]、……

    - 复合类型:List<Employee>、实体类中包含集合……

    <!-- 场景1 传入单个简单类型 key 随便写 一般情况下推荐使用参数名    -->

    <delete id="deleteById">

        delete from t_emp where emp_id=#{ergouzi}

    </delete>

    <select id="queryBySalary" resultType="org.example.pojo.Employee">

        select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_salary=#{salary}

    </select>

单个实体对象传入

注意:做插入,删除,更新操作时需要提交事务

    <!-- 场景2 传入的是一个实体对象 key 如何写?

              key = 对象的属性名即可

    -->

对应接口里的方法

    //插入员工数据【传入实体对象】

    int insertEmp(Employee employee);

    <insert id="insertEmp">

         insert into t_emp (emp_name,emp_salary) value (#{empName},#{empSalary});

    </insert>

多个简单类型传入

    <!-- 场景3 传入多个简单类型数据如何取值 key

              key 不可以随意取名

              key 也不可以按照形参名称取值

              方案一:注解指定 @Param注解  指定多个简单参数的key-----------------推荐使用

                       在形参前面加上此 @Param("标识") 形参类型 形参名;注解中的标识,就代表该形参,写对应key时就写该形参

        List<Employee> queryByNameAndSalary(@Param("name") String name,@Param("salary") Double salary);

              方案二:mybatis默认机制

                     arg0 arg1 ... 形参从左到右依次对应arg0,arg1...

                     (name,salary) name->key=arg0  salary->key=arg1

                     param1 param2 ...

                     (name,salary)name-> key=param1  salary->key=param2                    

        List<Employee> queryByNameAndSalary( String name, Double salary);

     -->

      <!--方案一:-->

    <select id="queryByNameAndSalary" resultType="org.example.pojo.Employee">

        select emp_id empId,emp_name empName,emp_salary empSalary

                 from t_emp where emp_name=#{name} and emp_salary=#{salary}

    </select>

     <--方案二:-->

    <select id="queryByNameAndSalary" resultType="org.example.pojo.Employee">

        select emp_id empId,emp_name empName,emp_salary empSalary

                 from t_emp where emp_name=#{arg0} and emp_salary=#{arg1}

    </select>

 返回值类型

返回单个简单类型   

    <!-- 返回单个简单类型如何指定     

         resultType的写法! 返回值的类型

         resultType语法:

               类的全限定符号

               别名简称

                  mybatis给我们提供了72种默认的别名!

                  这些都是我们常用的Java数据类型! 【Java常用的数据类型】

                       基本数据类型  int double -> _int _double

                       包装数据类型 Integer Double -> int/Integer double

                       集合容器类型 Map List HashMap -> 小写即可 map list hashmap

                  如果没有提供的需要自己定义或者写类的全限定符

         扩展 如果没有提供提供,需要自己定义或写类的全限定符

             给自己声明的类如何定义别名!!

               typeAliases>标签中定义:(该标签在setting下,environment——————mybatis-config.xml中)

               单独定义

               <typeAlias type="org.example.pojo.Employee" alias="employee"/>

               批量定义(批量将包下的类给与别名,别名为类名首字母小写!)

               <package name="org.example.pojo"/>  

     -->

    <select id="queryNameById" resultType="String">

        select emp_name empName from t_emp where emp_id=#{id}

    </select>

    <select id="querySalaryById" resultType="double">

        select emp_salary from t_emp where emp_id=#{id}

    </select>

返回单个自定义实体类型

    <!--场景2 返回当单个自定义实体类型

     resultType

           方式一:取类的全限定符

           方式二:取类的别名

      默认要求:

           查询,返回单个实体类型,要求列名和属性名要一致!

           这样才可以进行实体类的属性映射

      自动映射的设置方式:

      在mybatis-config.xml的setting标签中设置:

               开启驼峰式自动映射 数据库 a_column java aColumn

               <setting name="mapUnderscoreToCamelCase" value="true"/>    

     -->

    <select id="queryById" resultType="org.example.pojo.Employee">

        select * from t_emp where emp_id=#{id}

    </select>

返回map数据类型

对应方法:

    //查询部门的最高工资和平均工资

    Map<String,Object> selectEmpNameAndMaxSalary();

    <!-- 场景3 返回map数据类型

    对于放回的值没有实体类时可以使用map类型接收 (列名-》key;结果-》值)

    -->

    <select id="selectEmpNameAndMaxSalary" resultType="map">

        SELECT

        emp_name 员工姓名,

        emp_salary 员工工资,

        (SELECT AVG(emp_salary) FROM t_emp) 部门平均工资

        FROM t_emp WHERE emp_salary=(

        SELECT MAX(emp_salary) FROM t_emp

        )

    </select>

返回List集合类型数据

    <!-- 场景4 返回List集合类型

        //查询工资高于传入值的员工的姓名

        List<String> queryNameBySalary(Double salary);

        //查询全部员工信息

        List<Employee> queryAll();

        注意:返回值是集合时 resultType不是填list,而是填集合的泛型

        为什么:

        mybatis -> ibatis -> selectOne 单个|selectList 多个  -》selectOne调用selectList

    -->

    <select id="queryNameBySalary" resultType="string">

        select emp_name from t_emp where emp_salary>#{salary}

    </select>

    <select id="queryAll" resultType="org.example.pojo.Employee">

        select * from t_emp

    </select>

说明:返回结果时map类型时,需要查询结果映射,所以指定返回值类型为map,而list集合存储的只是对象,所以只需要指定泛型。

自动提交事务和自增长主键回显(返回主键值)

自动提交事务:在创建sqlSession时向openSession()方法中传入true

 例如sqlSession=sqlSessionFactory.openSession(true)

手动提交事务

sqlSession.commit();

自增长主键回显

    <!-- 场景5 主键回显 获取插入数据的主键

           1 自增长主键回显 由mysql维护 auto_increment

               //员工插入

               int insertEmp(Employee employee);

        想要主键回显 设置以下几个属性

        useGeneratedKeys="true"  我们想要数据库自动增长的主键值

        keyColumn="emp_id"   主键列的值(填入自增长主键列名)

        keyProperty="empId"  接收主键列值的属性

     -->

    <insert id="insertEmp" useGeneratedKeys="true" keyColumn="emp_id" keyProperty="empId">

        insert into t_emp (emp_name,emp_salary)

             value(#{empName},#{empSalary})

    </insert>

非自增长类型的维护

在teacharMapper.xml文件中

    <!--

将非自增长主键交由mybatis维护

    期望,非自增长主键,交给mybatis帮助我们维护!

<selectKey-------------------------插入语

    order="BEFORE|AFTER"  sql语句是在插入语句之前还是之后执行

    resultType="string"   插入语句返回值类型

    keyProperty="tId"    查询结果给那个属性赋值

    -->

    <insert id="insertTeacher">

        <selectKey order="BEFORE" resultType="string" keyProperty="tId">

            select replace(UUID(),'-','');

        </selectKey>

        insert into teacher (t_id,t_name)

        value(#{tId},#{tName})

    </insert>

多表映射

多表映射实体类设计

多表映射需要做的事

多表查询:

1多表查询的sql语句需要我们编写

2 自己设计存储数据的实体类(承接多个表查询的结果)

3自己定义结果集映射(resultMap)

多表实体类存储设计

实体类设计关系(查询):

实体类设计:对一关系下,类中只要包含单个对方对象类型属性即可!

实体类设计:对多关系下,类中只要包含对方类型集合属性即可!

深层映射

使用<resultMap标签、

    声明resultMap标签,自定义映射规则

        id标识-select resultMap=“标识

        type ->具体的返回值类型 全限定符和别名|集合只写泛型即可

             id  主键映射关系

             result  普通列映射关系

|关联关系

配置项关键词|所在配置文件和具体位置|

|对一

association标签/javaType属性/property属性|Mapper配置文件中的resultMap标签内|

|对多

collection标签/ofType属性/property属性|Mapper配置文件中的resultMap标签内|

格式:

    <resultMap id="代表此resultMap的标识" type="返回值类型">

        <!--

        第一层属性order对象

        id——————order的主键

        result——————order的普通列(customer_id在Customer表中是主键列,但在Order表中只是普通列)

        -->

        <id column="列名" property="对应属性名"/>

        <result column="列名" property="对应属性名"/>---------------如果开启了驼峰式映射reslut标签可省略

        <!--

          (对一)第二层对象属性赋值——————使用association标签

           property    对象属性名

           javaType    对象类型

           在association双标签中,<id  <result

        -->

        <association property="对象名" javaType="对象类型">

            <id column="列名" property="对应属性名"/>

            <result column="列名" property="对应属性名"/>

          注意:要开启深层映射

多表映射的优化-------------------------------开启深层映射

    默认情况下,resultMap会自动映射单层的result标签[前提:列名或属性名相同,或者开启了驼峰式映射后相同]

    嵌套association|collection不会自动映射result标签

    如何解决:开启深层次的自动映射

    在mybatis-config.xml文件的setting标签中

    <setting name="autoMappingBehavior" value="FULL"/>

    开启深层自动映射 不管resultMap有没有嵌套都会自动映射result标签的属性和列

        </association>

      (对多)    给集合属性赋值——————使用collection标签

    property   集合属性名

    ofType     集合的泛型类型

    在collection双标签中 <id <result

        <collection property="集合名" ofType="集合泛型">

            <id column="列名" property="对应属性名"/>

            <result column="列名" property="对应属性名"/>

        </collection>

    </resultMap>

代码举例

对一代码:   

@Data

public class Order {

    private Integer orderId;

    private String orderName;

    private Integer customerId;

    //一个订单对应一个客户 对一

    //对象装对应的客户信息

    private Customer customer;

}
public interface OrderMapper {

    //根据id查询订单信息和订单对应的客户

    Order queryOrderById(Integer id);

}

   在OrderMapper.xml中

<resultMap id="orderMap" type="order">

        <!--

        第一层属性order对象

        id——————order的主键

        result——————order的普通列(customer_id在Customer表中是主键列,但在Order表中只是普通列)

        -->

        <id column="order_id" property="orderId"/>

        <result column="order-name" property="orderName"/>

        <result column="customer_id" property="customerId"/>

       

        <!--

          第二层对象属性赋值——————使用association标签

           property    对象属性名

           javaType    对象类型

           在association双标签中,<id  <result

        -->

        <association property="customer" javaType="customer">

            <id column="customer_id" property="customerId"/>

            <result column="customer_name" property="customerName"/>

        </association>

       

    </resultMap>

   

    <select id="queryOrderById" resultMap="orderMap">

        SELECT * FROM t_order tor JOIN t_customer tur

        ON tor.`customer_id`=tur.`customer_id`

        WHERE tor.`order_id`=#{id}

    </select>

 

一对多代码

@Data

public class Customer {

    private Integer customerId;

    private String customerName;

    //一个客户对应多个订单

    //对多:装对方类型的集合即可

    private List<Order> orderList;

}
public interface CustomerMapper {

    //查询所有的客户信息以及客户对应的订单信息

    List<Customer> queryList();

}

在CustomerMapper.xml中

    <!--

    给集合属性赋值——————使用collection标签

    property   集合属性名

    ofType     集合的泛型类型

    在collection双标签中 <id <result

    -->

    <resultMap id="customerMap" type="customer">

        <id column="customer_id" property="customerId"/>

        <result column="customer_name" property="customerName"/>

        <collection property="orderList" ofType="order">

            <id column="order_id" property="orderId"/>

            <result column="order_name" property="orderName"/>

            <result column="customer_id" property="customerId"/>

        </collection>

    </resultMap>

    <select id="queryList" resultMap="customerMap">

        SELECT * FROM t_order tor JOIN t_customer tur

        ON tur.`customer_id`=tor.`customer_id`

    </select>

 

相关文章:

  • VsCode启用右括号自动跳过(自动重写) - 自录制gif演示
  • 26考研——栈、队列和数组_数组和特殊矩阵(3)
  • 力扣刷题-热题100题-第24题(c++、python)
  • 代码规范之Variable Names变量名
  • 如何使用 CSS 实现多列布局,有哪些注意事项
  • 一款可查看手机详细配置信息的小工具,简单直观,自动识别硬件信息
  • 创建一个服务器启动自动执行的脚本,设置默认路由
  • LUMOS: Language-Conditioned Imitation Learning with World Models
  • QT三 自定义控件,自定义控件的事件处理自定义事件过滤,原始事件过滤
  • 爬虫——将数据保存到MongoDB中
  • conda极速上手记录
  • 如何部署自己的本地大模型
  • Hadoop三 分布式sql计算hive入门
  • 基于PyTorch的艺术风格迁移系统:卷积神经网络与迁移学习在图像生成的应用
  • 【Node.js入门教程:从零到精通】
  • 关于优麒麟ukylin如何更换清华源以及ubuntu24.04安装gcc-i686-linux-gnu找不到包的问题
  • AI视频生成技术的革新之路:Video-T1项目的深度解析
  • 计算机期刊推荐 | 计算机-人工智能、信息系统、理论和算法、软件工程、网络系统、图形学和多媒体, 工程技术-制造, 数学-数学跨学科应用
  • 深度分页优化思路
  • 数据可视化TensorboardX和tensorBoard安装及使用
  • 荣盛发展股东所持1.17亿股将被司法拍卖,起拍价约1.788亿元
  • “面具女孩”多次恐吓电梯内两幼童,当事女孩及家长道歉后获谅解
  • 启程回家!神十九轨道舱与返回舱成功分离
  • 安徽省公安厅原副厅长刘海石主动投案,正接受审查调查
  • 新造古镇丨上海古镇朱家角一年接待164万境外游客,凭啥?
  • 当AI开始深度思考,人类如何守住自己的慢思考能力?