Mybatis框架学习

news2024/12/24 3:36:06

什么是mybatis?

mybatis是一款用于持久层的、轻量级的半自动化ORM框架,封装了所有jdbc操作以及设置查询参数和获取结果集的操作,支持自定义sql、存储过程和高级映射

mybatis用来干什么?

用于处理java和数据库的交互

使用mybatis的好处

  1. 与JDBC相比,减少了50%以上的代码量。
  2. MyBatis灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL可以写在XML里(还可以以注解方式写到Java代码中),从程序代码中彻底分离,降低耦合度,便于统一管理和优化,可重用。
  3. 提供XML标签,支持编写动态SQL语句(XML中使用 if, else 等)

使用mybatis

下载Mybatis的jar包:Releases · mybatis/mybatis-3 (github.com)

创建xml文件:mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

修改内容:

SqlSessionFactoryBuilder

通过SqlSessionFactoryBuilder可创建多个SqlSessionFactory实例

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(new FileInputStream("mybatis-config.xml"));

SqlSessionFactory

通过SqlSessionFactory创建多个会话,SqlSession对象,每个会话就相当于我不同的地方登陆一个账号去访问数据库。

一般SqlSessionFactory只需要创建一次

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(new FileInputStream("mybatis-config.xml"));

SqlSession

使用 MyBatis 的主要 Java 接口就是 SqlSession。你可以通过这个接口来执行命令,获取映射器实例和管理事务。SqlSession实例可直接执行已映射的sql语句。

确保SqlSession关闭的标准模式:

//try-with-resource
try(SqlSession session = sqlSessionFactory.openSession()) {
            
}

XML映射语句

基于XML映射语句,便可满足sqlsession的调用

例如简单的select语句

<?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">
<mapper namespace="TestMapper">
    <select id="selectEmployee" resultType="com.test.entity.Employee">
        select * from employee where id = #{id}
    </select>
</mapper>

参数符号:#{id},这就告诉 MyBatis 创建一个预处理语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个?来标识,并被传递到一个新的预处理语句中.

MybatisUtil工具类

创建MybatisUtil工具类,以便集中创建SqlSession

public class MybatisUtil {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(new FileInputStream("mybatis-config.xml"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取一个新的会话
     * @param autoCommit 是否开启自动提交(跟JDBC是一样的,如果不自动提交,则会变成事务操作)
     * @return SqlSession对象
     */
    public static SqlSession getSession(boolean autoCommit){
        return sqlSessionFactory.openSession(autoCommit);
    }
}

方便使用:

public class Main {
    public static void main(String[] args) throws FileNotFoundException {
        try(SqlSession session = MybatisUtil.getSession(true)) {
            TestMapper mapper = session.getMapper(TestMapper.class);
            
        }
    }
}

映射器接口

映射器是一些用来绑定映射语句的接口。创建com.test.mapper包,创建接口TestMapper。

这样做好处是将映射器的结果快速转换为需要的实体类,通过XML中的namespace绑定接口

  • 全限定名(比如 “com.test.mapper.TestMapper")将被直接用于查找及使用。
<mapper namespace="com.test.mapper.TestMapper">
    <select id="selectEmployee" resultType="com.test.entity.Employee">
        select * from employee
    </select>
</mapper>

将接口与XML放在同包资源中,修改mybatis-config.xml文件

    <mappers>
        <mapper resource="com/test/mapper/TestMapper.xml"/>
    </mappers>

XML配置属性typeAliases

typeAliases,类型别名,简化Mapper的缩写

<configuration>
    <typeAliases>
        <typeAlias type="com.test.entity.Employee" alias="Employee"/>
    </typeAliases>
    <environments default="development">
        ........

在这里插入图片描述

或直接扫描包,默认别名为小写的开头

    <typeAliases>
        <package name="com.test.entity"/>
    </typeAliases>

也可写注解来指定别名

@Alias("employee")
public class Employee {
    ...
}

ResultMap

当类中定义的字段与数据库的字段不统一时,用ResultMap来映射到对应的实体

column:数据库中的字段,property:java中编写的字段名称

<mapper namespace="com.test.mapper.TestMapper">
    <resultMap id="Test" type="Employee">
        <result column="id" property="xxx"/>
    </resultMap>
    <select id="selectEmployee" resultMap="Test">
        ....

多个构造器如何选择

当有多个构造器,优先选择满足全部字段的构造器,如果没有则报错

在这里插入图片描述

如果只有一个构造器,不管满足几个字段,都会调用

那如果就是没有满足的呢?那就要用constructor

<mapper namespace="com.test.mapper.TestMapper">
    <resultMap id="Test" type="Employee">
        <constructor>
            <arg column="id" javaType="Integer"/>
            <arg column="name" javaType="String"/>
        </constructor>
      	<result column="id" property="xxx"/>
    </resultMap>
        .......

注意:这样写的话,构造器中形参需要对象类型,比如如果用int不用Interger,会报错:

在这里插入图片描述

另外,这样写的话构造器中的字段并不会映射到,因为映射器已经交给构造器来处理了。

bug:绑定错误

Exception in thread “main” org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

解决:select中id与接口绑定错误,记得要一致

在这里插入图片描述

在这里插入图片描述

增删改查

创建接口实例

TestMapper mapper = session.getMapper(TestMapper.class);

TestMapper.xml中编写sql语句

<mapper namespace="com.test.mapper.TestMapper">
    <select id="getEmployeeId" resultType="Employee">
        select * from employee where id = #{id}
    </select>

    <insert id="addEmployee" parameterType="Employee">
        insert into employee (id, name, sex, age, salary) values (#{id}, #{name}, #{sex}, #{age}, #{salary})
    </insert>

    <delete id="deleteEmployee">
        delete from employee where id = #{id}
    </delete>
</mapper>

在这里插入图片描述

通过接口实例直接调用接口中的方法

update操作

mapper:

<update id="updateStudent" parameterType="student">
	update student set sex = #{sex} where sid = #{sid}
</update>

mapper接口:

int updateStudent(Student student);

测试:

Student student = mapper.getStudentSid(1940618805);
student.setSex("女");
mapper.updateStudent(student);

复杂查询

多表查询一对多:例如查询一个老师教多少个学生

collection:用于一对多关系,即实体里面放集合

<resultMap id="asTeacher" type="Teacher">
        <id column="tid" property="tid"/>
        <result column="tname" property="name"/>
        <collection property="studentList" ofType="Student">
            <id property="sid" column="sid"/>
            <result column="name" property="name"/>
            <result column="sex" property="sex"/>
        </collection>
</resultMap>  
    <select id="getTeacherByTid" resultMap="asTeacher">
        select *, teacher.name as tname from student inner join teach on student.sid = teach.sid
                                        inner join teacher on teacher.tid where teach.tid = #{tid}
    </select>

<id column="tid" property="tid"/>

id用于唯一标识一个老师

多表查询多对一:如果要求学生类增加一个老师属性,即根据教师id来找教师的所有学生

association:用于多对一关系

    <resultMap id="test2" type="Student">
        <id column="sid" property="sid"/>
        <result column="name" property="name"/>
        <result column="sex" property="sex"/>
        <association property="teacher" javaType="Teacher">
            <id column="tid" property="tid"/>
            <result column="tname" property="name"/>
        </association>
    </resultMap>

    <select id="selectStudent" resultMap="test2">
        select *, teacher.name as tname from student left join teach on student.sid = teach.sid
            left join teacher on teach.tid = teacher.tid where teach.tid = #{tid}
    </select>

事务处理

自动提交关闭:

SqlSession session = MybatisUtil.getSession(false)

手动提交

session.commit();

动态SQL

if

test 为if的条件,如果为真,则拼接if标签里面的and语句,如查询学号是偶数的男同学

    <select id="getStudentSid" resultType="student">
        select * from student where sid = #{sid}
        <if test="sid % 2 == 0">
            and sex = '男'
        </if>
    </select>

choose,when,otherwise

类似于switch,case,default

<select>
    <choose>
    	<when test = "">
        	and...
    	</when>
    	<when test = "">
        	and...
    	</when>
    
    	<otherwise>
        	and...
    	</otherwise>
	</choose>
</select>

where

where元素只会在有子元素有返回的情况下才会插入where,并且如果子元素的开头是and,or,(显然sql语句中 where and…是语法错误的吧),where元素会将他们去除

        select * from student
        <where>
            <if test="sid != null">
<!--                and sid = #{sid}-->
                sid = #{sid}
            </if>
        </where>

set

    <update id="updateStudent">
        update student
        <set>
            <if test="name != null">
                name = #{name}
            </if>
        </set>
        where sid = #{sid}
    </update>

缓存机制

查询出的对象存入SqlSession的一级缓存,如果后续有相同操作,则之间从缓存中获取,不需要重新构造一个对象,提高效率

Student student = mapper.getStudentSid(1940618805);
Student student1 = mapper.getStudentSid(1940618805);
System.out.println(student1 == student); // true

但是,如果在该两次相同的操作中,对数据库内容进行了增,删,改操作,则会清除缓存

并且,每一个SqlSession会话的一级缓存是分开来的。即在不同的会话下,上述操作得到的不是同一个对象

一级缓存也叫做本地缓存,它只对一个会话的数据进行缓存。

要使用全局的缓存,是需要开启二级缓存。只需要在mapper文件中加上

<cache/>
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

开启二级缓存后,不同会话中连续的相同操作也会直接从缓存中获取对象。(同样的,如果在这两次操作之间对数据库内容进行了增,删,改操作,则会清除缓存)

但是,多个会话时,只有当一个会话结束了才会将数据从一级缓存写入二级缓存:

public class Main {
    public static void main(String[] args) throws FileNotFoundException {
        try(SqlSession session1 = MybatisUtil.getSession(true);
            SqlSession session2 = MybatisUtil.getSession(true)) {
            TestMapper mapper1 = session1.getMapper(TestMapper.class);
            TestMapper mapper2 = session2.getMapper(TestMapper.class);

            Student student1 = mapper1.getStudentSid(1940618806);
            Student student2 = mapper2.getStudentSid(1940618806);
            System.out.println(student1 == student2); // false 获取对象时会话未结束,二级缓存没有内容
        }
    }
}

注解开发

去除mapper xml文件,直接在mapper接口方法上写上注解

@Insert("insert into student(sid, name, sex) values(#{sid}, #{name}, #{sex})")
int addStudent(Student student);

使用注解开发需要修改mybatis配置文件的mappers

    <mappers>
        <mapper class="com.test.mapper.TestMapper"/>
<!--        <package name="com.test.mapper"/>-->
    </mappers>

自定义映射规则

@Results

    @Results({
            @Result(id = true, column = "sid", property = "sid"),
            @Result(column = "name", property = "name"),
            @Result(column = "sex", property = "sex")
    })
    @Select("select * from student where sid = #{sid}")
    Student getStudentSid(int sid);

一对多查询,如一个教师教的学生

@Many(select="")

这个就是一对多关系中联结查询的条件

    @Results(value = {
            @Result(column = "tid", property = "tid"),
            @Result(column = "name", property = "name"),
            @Result(column = "tid", property = "studentList", many =
            @Many(select = "getStudentByTid"))
    })
    @Select("select * from teacher where tid = #{tid}")
    Teacher getTeacherByTid(int tid);

    @Select("select * from student inner join teach on student.sid = teach.sid")
    List<Student> getStudentByTid(int tid);

@Param()

当select语句有多个参数条件时,使用@Param()

    @Select("select * from student where sid = #{sid} and sex = #{sex}")
    Student getStudentBySidAndSex(@Param("sid")int sid, @Param("sex")String sex);

否则报错

### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'sid' not found. Available parameters are [arg1, arg0, param1, param2]

这是因为多个参数时,mybatis并不知道这些属性是哪里来的,“Parameter xxx not found”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1024693.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

容器中的nginx暴露一个端口部署多个功能的网站

随着容器的应用越来越多&#xff0c;将nginx部署在容器中也是常有之事。可能事先创建容器时只暴露了一个端口给浏览器连接&#xff0c;后面又想根据添加多个应用&#xff0c;根据URL的不同来访问不同的应用。比如在暴露了主机的83端口给nginx容器的80端口&#xff0c;原来只有一…

华为云云耀云服务器L实例评测|宝塔一站式安装数据库MySQL+Redis教程

目录 前言 一、传统服务器安装数据库 1.安装MySQL 2.安装Redis 二、云耀云服务器L安装MySQL 1.云耀云服务器L实例购买 2.远程登录并重置密码 3.云耀云服务器L初始化宝塔面板 4.宝塔面板安装数据库 5.MySQL第三方登录 三、云耀云服务器L安装Redis 1.宝塔面板安装Redis 2.Redis密…

JumpServer未授权访问漏洞 CVE-2023-42442

JumpServer未授权访问漏洞 CVE-2023-42442 一、漏洞描述二、漏洞影响三、网络测绘四、漏洞复现poc通过burp发送请求包小龙POC检测 五、修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接…

【正则表达式】

正则表达式 1 本节目标2 正则表达式概述2.1 什么是正则表达式2.2 正则表达式的特点 3 正则表达式在JavaScript中的使用3.1 创建正则表达式3.2 测试正则表达式test 4 正则表达式中的特殊字符4.1 正则表达式的组成4.2 边界符4.3 字符类4.4 量词符4.5 括号总结4.6 预定义类 5 正则…

如何分清PMP和NPDP?一篇文足以

先简单介绍一下两个证书&#xff1a; PMP&#xff1a;项目管理证书&#xff0c;项目经理 英文全称是Project Management Professional&#xff0c;中文全称叫做项目管理专业人士资格认证。 它是由美国项目管理协会&#xff08;PMI&#xff09;在全球范围内推出的针对项目经理…

mojo安装

docker安装mojo 官网 https://developer.modular.com/login 很奇怪登录页面不显示 类似于网站劫持 docker 安装mojo带jupyterlab的方式 https://hub.docker.com/r/lmq886/mojojupyterlab 拉取镜像 docker pull lmq886/mojojupyterlab docker pull lmq886/mojojupyterlab:1.2 启…

没有任何销售经验怎么管理销售团队?

本文将为大家讲解&#xff1a;1、什么是销售管理&#xff1f;2、销售管理的流程是什么&#xff1f;3、如何进行销售管理&#xff1f;4、crm客户管理系统对于销售管理有什么样的作用&#xff1f;5、2023年最全crm客户管理系统推荐。 一、什么是销售管理&#xff1f; 根据美国营…

【数据结构与算法】一文带你学透——算法概述

前言 本期我们所要学习的内容是数据结构与算法中的算法的相关内容&#xff0c;通过上期我们学的数据结构想必大家都会了吧&#xff0c;在学习完毕之后算法&#xff0c;我想你已经可以编写出比较优秀的代码了&#xff0c;著名计算机科学家沃思曾提出一个公式 程序数据结构算法。…

18.备忘录模式(Memento)

意图&#xff1a;在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;这样就可以在以后将该对象恢复到原先保存的状态。 上下文&#xff1a;某些对象的状态在转换过程中&#xff0c;可能由于某种需要&#xff0c;要求…

Python的电机控制模拟程序

一个带有EPICS支持的虚拟电机控制器。 1&#xff09;Status类&#xff1a;其实例化对象代表一个电机轴的状态。 #!/usr/bin/env python Status类代表一个电机处于的状态&#xff1a;1、DIRECTION状态位&#xff1a;设置运动方向2、DONE_MOVING状态字&#xff1a;置位表示结束…

数据结构与算法的力量:编写更高效的代码

文章目录 为什么数据结构和算法重要&#xff1f;1. 提高性能2. 节省资源3. 解决复杂问题4. 改进代码质量 常见数据结构和算法数据结构1. 数组&#xff08;Array&#xff09;2. 链表&#xff08;Linked List&#xff09;3. 栈&#xff08;Stack&#xff09;4. 队列&#xff08;Q…

哈希(hash)——【C++实现】

本章gitee代码仓库&#xff1a;Hash 文章目录 &#x1f490;1. 哈希概念&#x1f33b;2. 哈希冲突&#x1f33c;3. 哈希函数&#x1f338;3.1 哈希函数设计原则&#x1f338;3.2 常见哈希函数 &#x1fab4;4. 哈希冲突解决方案&#x1f331;4.1 闭散列——开放定址法&#x1f…

Android存储权限完美适配(Android11及以上适配)

一、Bug简述 一个很普通的需求&#xff0c;需要下载图片到本地&#xff0c;我的三个测试机&#xff08;荣耀Android10&#xff0c;红米 11 和小米Android 13都没有问题&#xff09;。 然后&#xff0c;主角登场了&#xff0c;测试的三星Android 13 死活拉不起存储权限弹窗。 …

使用setInterval定时器实现文字一个一个的打印在页面中

前言&#xff1a; 项目需求实现请求回来的数据一个一个的打印在页面中&#xff0c;点击“停止生成”暂停打印&#xff1b;该功能需求类似于文心一言。 代码实现&#xff1a; view页面代码&#xff1a; script代码&#xff1a; 核心代码&#xff1a; let k 0; timer setInte…

【python】lightgbm 无法打开文件

问题&#xff1a;文件无法打开 在使用 lightgbm 读取模型文件时不能打开 报错&#xff1a; Traceback (most recent call last):File "detect_interpretability_.py", line 176, in <module>lightgbm_test(White_data, os.path.basename(data_path), model_f…

得帆信息联合创始人——王周健:大中型企业集成平台选型建议

在当今这个数字化时代&#xff0c;大中型企业面临着前所未有的挑战&#xff0c;企业需要快速响应外部市场变化&#xff0c;以保持竞争力。在这个过程中&#xff0c;企业需要快速、准确的决策力&#xff0c;需要大量有价值的数据作为支撑。所以跨企业、跨部门、跨系统的业务联通…

C语言字符函数和字符串函数(1)

大家好&#xff0c;我们又见面了&#xff0c;让大家久等了&#xff0c;我们今天就来学习字符函数和字符串函数。 在开启今天的学习之前呢&#xff0c;我来解决一下一些小伙伴平时找不到库函数使用的烦恼&#xff0c;因为我们cplusplus.com最新版本不能够查询函数&#xff0c;我…

C盘扩容(微PE工具箱)

C盘扩容&#xff08;微PE工具箱&#xff09; 1、关闭Bitlocker2、安装微PE3、以D盘分10G给C盘为例3.1安装后重启会出现两个选项电脑系统和PE系统&#xff0c;选择PE系统3.2调成分区空间3.3检查分盘情况并删除PE系统 1、关闭Bitlocker 2、安装微PE https://www.wepe.com.cn/dow…

2023年招标行业研究报告

第一章 行业概况 1.1 招标定义和分类 招标行业涉及政府、企事业单位通过公开、公平、公正的手段组织采购、工程建设等项目的过程。尽管中国的招标行业发展历程相对较短&#xff0c;但随着市场经济的深入发展和政府采购制度的持续改革&#xff0c;该行业已逐渐崭露头角&#x…

《遇见秋分》公众号排版模板,感受秋天的文艺唯美

秋分,是二十四节气之第十六个节气,秋季第四个节气。秋分这天太阳几乎直射地球赤道,全球各地昼夜等长。秋分&#xff0c;“分”即为“平分”、“半”的意思,除了指昼夜平分外,还有一层意思是平分了秋季。秋分日后,太阳光直射位置南移,北半球昼短夜长&#xff0c;昼夜温差加大,气…