Mybatis基础

本文详细介绍了MyBatis的持久层框架,包括概念、内部结构、入门案例,涵盖了配置文件、映射文件、ORM、参数解析、SQL特殊字符处理、动态SQL以及接口映射方式。通过实例演示了如何设置别名、参数类型、结果映射,以及如何使用MyBatis进行数据库操作和测试。
摘要由CSDN通过智能技术生成

一、MyBatis持久层框架

1、概念

MyBatis的前身就是iBatis,iBatis本是apache的一个开源项目,2010年5月这个项目由apahce sofeware foundation 迁移到了google code,并且改名为MyBatis。

MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。

1)简化JDBC的开发
2)能够更好的完成ORM(对象关系映射)
3)核心配置文件 – 用来配置数据库的连接的参数
4)映射文件 – 用来写SQL

两个核心的工具类:
1)SqlSessionFactory – 会话工厂,用来产生会话
2)SqlSession – 会话,用来执行SQL
3)ORM:对象关系映射,是指把表里字段的值 自动映射给 类里的属性

2、内部组件结构图

在这里插入图片描述

二、入门案例

1、准备数据表—数据库

create database mybatisdb default character set utf8;
use mybatisdb;
create table user(id int primary key auto_increment,name varchar(100),addr varchar(100),age int);
Insert into user values(null,'hanmeimei','北京',28);
Insert into user values(null,'xiongda','上海',20);
Insert into user values(null,'xiaonger','上海',19);
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `dname` varchar(14) DEFAULT NULL,
  `loc` varchar(13) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES ('1', '呵呵呵', '一区');
INSERT INTO `dept` VALUES ('2', '哈哈哈哈', '二区');
INSERT INTO `dept` VALUES ('3', 'operations', '二区');
INSERT INTO `dept` VALUES ('5', 'java教研部', '大钟寺');
INSERT INTO `dept` VALUES ('10', '开发', '西二旗');
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ename` varchar(10) DEFAULT NULL,
  `job` varchar(9) DEFAULT NULL,
  `mgr` decimal(4,0) DEFAULT NULL,
  `hiredate` date DEFAULT NULL,
  `sal` decimal(7,2) DEFAULT NULL,
  `comm` decimal(7,2) DEFAULT NULL,
  `deptno` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=510 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES ('100', 'jack', '副总', null, '2002-05-03', '90000.00', null, '1');
INSERT INTO `emp` VALUES ('200', 'tony', '总监', '100', '2015-02-02', '10000.00', '2000.00', '2');
INSERT INTO `emp` VALUES ('300', 'hana', '经理', '200', '2017-02-02', '8000.00', '1000.00', '2');
INSERT INTO `emp` VALUES ('400', 'leo', '员工', '300', '2019-02-22', '3000.00', '200.12', '2');
INSERT INTO `emp` VALUES ('500', 'liu', '员工', '300', '2019-03-19', '3500.00', '200.58', '2');
INSERT INTO `emp` VALUES ('502', '王一博', 'topidol.', '1000', '2021-03-31', '20000.00', '99.00', '88');
INSERT INTO `emp` VALUES ('504', '蔡徐坤', 'rapper', '10', '2021-03-29', '100.00', '1000.00', '100');

2、Maven工程结构

在这里插入图片描述
=注:导入jUnit5,使用@BeforeEach注解替代jUnit4的@Before。

3、修改pom文件,添加mybatis的jar包依赖,pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cgb2105sboot01</artifactId>
        <groupId>cn.tedu</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatusdbday17</artifactId>
    <dependencies>
        <!--jdbc依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>
        <!--mybatis依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>


</project>

4、创建User类,User.java

package cn.tedu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

//完成ORM,把表里的字段的值 查到 封装给类里的属性
//lombok标签,用来自动创建get、set、tostring、构造方法等
@Data 
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true) //开启链式编程
//Mybatis自动完成ORM,把表里的字段的值 查到 封装给 类里的属性
//要求:属性名要和字段名一样
public class User {
   private Integer id;
   private String name;
   private String addr;
   private String age;
}

4、创建核心配置文件,指定连接数据库的参数,mybatis-config.xml

步骤:new------file------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">

<!-- mybatis的核心配置文件 -->
<configuration>
    <!--用来设置别名 type是类的全路径 alisa是以后要使用的别名-->
    <typeAliases>
        <typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
        <typeAlias type="cn.tedu.pojo.Dept" alias="Dept"></typeAlias>
    </typeAliases>

    <!--可以配置多个数据库连接的环境,使用default指定默认用哪个-->
    <environments default="test">
        <!--配置了具体连接数据库的参数-->
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源:就是制定了数据库连接时的参数-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="UseMapper.xml"/>
        <mapper resource="DeptMapper.xml"/>
    </mappers>
</configuration>

5、创建映射文件,写SQL,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="UserMapperNS">
    <!--select标签表示要发起查询的SQL,
    id是SQL语句的唯一标识,
    resultType用来完成ORM,把表里的字段值 自动映射 类里的属性
    -->
    <!--查询user表中所有的信息-->
    <select id="getAll" resultType="cn.tedu.pojo.User">
        select * from user
    </select>

    <!--查询id=1的user信息-->
    <select id="getById" resultType="cn.tedu.pojo.User">
        select * from user where id = 1
    </select>

    <!--动态查询id=?的user信息
        select* from user where id=1 不要把参数1写死,太死板了
        ${???}动态获取执行SQL时传入的参数
    -->
    <select id="getId" resultType="User">
        select * from user where id = ${id}
    </select>

    <!--动态查询user信息-->
    <select id="getName" resultType="User">
     <!--
     	面试题:$ 和 #取值的区别?
        都能获取参数的值,$只获取值本身不拼接单引号,#获取到值以后自动拼接单引号
        $底层使用Statement不安全低效,#底层使用PreparedStatement高效安全SQL简单
        select * from user where name = ${name}
        -->
        select * from user where name = #{name}
    </select>

    <!--动态查询user信息-->
    <select id="getIdName" resultType="User">
        select * from user where name = #{name} and id = #{id}
    </select>

    <!--查询上海有几个人-->
    <!--
    	resultType是指查询的结果要交给谁处理,
        结果可以是写一个类的路径,也可以写int string等
    -->
    <select id="getAddr" resultType="int">
        select count(1) from user where addr = #{addr}
    </select>
</mapper>

6、修改核心配置文件,加入映射文件

  <!--引入映射文件-->
    <mappers>
        <mapper resource="UseMapper.xml"/>
        <mapper resource="DeptMapper.xml"/>
    </mappers>

7、创建单元测试类,Test.java

package cn.tedu;

import cn.tedu.pojo.Dept;
import cn.tedu.pojo.User;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;
import java.io.InputStream;
import java.util.List;

//测试
public class test {
    @Test
    public  void get() throws Exception {
        //1、读取核心配置文件---创建字节输入流对象用于读取
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

        //2、创建会话工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

        //3、创建会话
        SqlSession session = factory.openSession();

        //4、执行sql
        //List<Object> getAll = session.selectList("namespace的值.id的值"); 唯一的定位的sql
        List<User> list = session.selectList("UserMapperNS.getAll"); //查询出多个结果

        //4、处理结果
        for (User u: list) {
            System.out.println(u);
        }

        User user = session.selectOne("UserMapperNS.getById");//查询出一个结果
        System.out.println(user);

        //动态查询id=2的信息
        User user1 = session.selectOne("UserMapperNS.getId",2);//查询出一个结果
        System.out.println(user1);

        //动态查询name=xiaonger的信息
        //selectOne(1,2)--1是SOL定位的方式,2是soL需要的参数
        User user2 = session.selectOne("UserMapperNS.getName", "xiaonger");//查询出一个结果
        System.out.println(user2);

        //动态查询name=xiaonger的信息
        //selectlist(1,2)--1是SOL定位的方式,2是soL需要的参数
        List<User> list1 = session.selectList("UserMapperNS.getName", "xiaonger");//查询出一个结果
        for (User u: list1) {
            System.out.println(u);
        }

        int count = session.selectOne("UserMapperNS.getAddr", "上海");
        System.out.println(count);

    }
}

8、测试

在这里插入图片描述

三、参数解析

1、别名:alias

sqlMapConfig.xml配置,在映射文件中直接写对象名称即可

设置别名:修改核心配置文件,加一个typeAliases标签
<!--用来设置别名 type是类的全路径 alisa是以后要使用的别名-->
    <typeAliases>
        <typeAlias type="cn.tedu.pojo.User" alias="User"></typeAlias>
        <typeAlias type="cn.tedu.pojo.Dept" alias="Dept"></typeAlias>
    </typeAliases>
使用别名:在映射文件里,在resultType处直接使用别名
<select id="getAll" resultType="User">
    select * from user
 </select>

2、参数值:paramterType

指定参数类型,通常制定一个对象类型。

3、返回值:resultType

非常重要的东西,即完成ORM的映射关系所在。
这里将指定的cd.tedu.mybatis.domain.User代表 把 结果集 转换成一个User 对象实例。

4、返回值:resultMap

resultMap 用于对复杂对象结构时,对应的ResultMap结构名称

5、#和$的区别

两种方式都可以获取参数的值。区别如下:

推荐!)#:

使用#{parameterName}引用参数的时候,Mybatis会把这个参数认为是一个字符串,例如传入参数是"Smith",那么在SQL(Select * from emp where name = #{employeeName})使用的时候就会转换为Select * from emp where name = ‘Smith’。
在这里插入图片描述

$:

不做字符串拼接,SQL(Select * from emp where name = ${employeeName})使用的时候就会转换为Select * from emp where name = Smith。此时,如果字段是varchar类型直接抛出SQL异常。
在这里插入图片描述

总结:
都能获取参数的值,
$只获取值本身不拼接单引号
#获取到值以后自动拼接单引号
$底层使用Statement不安全低效
#底层使用PreparedStatement高效安全SQL简单

6、xml的转义符号

在xml文件中,一些符号比较特殊,需要转译
xml文档中,定义了一些实体,以&开始,以;结束

代码符号解释
&lt;<小于号
&git;>大于号
&amp;&
&apos;单引号
&quot"双引号

四、SQL中有特殊字符

当SQL中有特殊字符,mybatis不能正常解析时,
用<![CDATA[ ?? ]]>括起来就解决了 <![CDATA[ and age<=#{age} ]]>

<![CDATA[
	and age<=#{age}
]]>

五、动态SQL

Mybatis提供使用ognl表达式动态生成sql的功能。

1、sql和include

Sql标签用来提取SQL片段,来提高SQL的复用.

使用位置需要通过include引用指定的SQL片段.

  <!-- 提取sql片段 -->
    <sql id="names">
        id,dname,loc
    </sql>

    <!--查询dept表中所有的信息-->
    <select id="getAll" resultType="Dept">
        <!-- 引入标签前的代码:select * from dept-->
        <!--引入后-->
        /* include引入sql片段,refid指定sql片段的id值 */
        select <include refid="names"></include>
        from dept
    </select>

2、if

执行SQL时,可以添加一些判断条件

 <!--查询id=1的记录 if判断-->
    <select id="getId1" resultType="Dept">
        select <include refid="names"></include>
        from dept
        <!-- 使用if标签用来判断,条件成立才执行sql,不成就不执行-->
        <if test="id != null">
            where id = #{id}
        </if>

    </select>

3、where

去掉条件中可能多余的and或者or

<!--查询id=1或者3的部门信息 where 去除多余的and或者or-->
	<select id="getIds" resultType="Dept">
		select
		<include refid="names"></include>
		from dept
		<!-- 使用if标签用来判断,条件成立才执行sql,不成就不执行-->
		<where>
			<if test=" id != null ">
				id =#{id}
			</if>
			or id =3
		</where>
	</select>

4、set

去掉最后可能多余的逗号:

<update id="update">
UPDATE teachers 
<set>
		<if test="tname != null">tname=#{tname},</if>
		<if test="tsex != null">tsex=#{tsex},</if>
		<if test="tbirthday != null">tbirthday=#{tbirthday},</if>
		<if test="prof != null">prof=#{prof},</if>
		<if test="depart != null">depart=#{depart}</if>
</set>
WHERE tno=#{tno}	
</update>

5、foreach

用于in子查询中的多个值的遍历:

<!--删除id 1,2,3的数据-->
	<select id="delId1">
		<!--delete from dept where id in(1,2,3),参数写死了,最好动态解析-->
		delete from dept where id in
		<!--
			foreach用来遍历,collection属性的值是固定值array list map里的key
			item相当于遍历得到的数据 separator是数据间的分隔符
			open是开始,close是结束
		-->
		<foreach collection="array" item="i" separator="," open="(" close=")">
			#{i}
		</foreach>
	</select>

调用代码:

 //id=1或者3的部门信息
        List<Dept> list7 = session.selectList("DeptMapperNS.getIds",19);
        for (Dept d : list7) {
            System.out.println(d);
        }

        //删除id 1,2,3的数据
        Integer[] arr = {1,2,3};
        session.delete("DeptMapperNS.delId1",arr);
        //

6、案例

6.1、添加依赖,pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cgb2105sboot01</artifactId>
        <groupId>cn.tedu</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatisdbday18</artifactId>
    <dependencies>
        <!--lombok依赖包-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--jdbc依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>

        <!--mybatis依赖包-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
    </dependencies>



</project>
6.2、Dept类,Dept.java
package cn.tedu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

//Mybatis自动完成ORM,把表里的字段的值 查到 封装给 类
//要求:属性名要和字段名一样

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Dept {
    private Integer id;
    private String dname;
    private String loc;
}
6.3、核心配置文件,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">

<!-- mybatis的核心配置文件 -->
<configuration>
    <!--用来设置别名 type是类的全路径 alisa是以后要使用的别名-->
    <typeAliases>
        <typeAlias type="cn.tedu.pojo.Dept" alias="Dept"></typeAlias>
    </typeAliases>

    <!--可以配置多个数据库连接的环境,使用default指定默认用哪个-->
    <environments default="test">
        <!--配置了具体连接数据库的参数-->
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源:就是制定了数据库连接时的参数-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="DeptMapper.xml"/>
    </mappers>
</configuration>
6.4、DeptMapper.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="cn.tedu.dao.DeptDao">
	<!--select标签表示要发起查询的SQL,
	id是SQL语句的唯一标识,
	resultType用来完成ORM,把表里的字段值 自动映射 类里的属性
	-->
	<!-- 提取sql片段 -->
	<sql id="names">
        id,dname,loc
    </sql>

	<!--静态查询dept表中所有的信息-->
	<!--resultType使用了别名,因为在核心配置文件里配过了 -->
	<select id="getAll1" resultType="Dept">
        select * from dept;
    </select>

	<!--动态查询dept表中所有的信息-->
	<select id="getAll" resultType="Dept">
		<!-- 引入标签前的代码:select * from dept-->
		<!--引入后-->
		/* include引入sql片段,refid指定sql片段的id值 */
		select
		<include refid="names"></include>
		from dept
	</select>

	<!--查询name=java教研部 的部门表部门信息 -->
	<select id="getName" resultType="Dept">
		select
		<include refid="names"></include>
		from dept
		where
		dname = #{dname}
	</select>

	<!--查询name=java教研部 的部门表部门信息 if判断-->
	<select id="getName1" resultType="Dept">
		select
		<include refid="names"></include>
		from dept
		<!-- 使用if标签用来判断,条件成立才执行sql,不成就不执行-->
		<if test=" dname != null ">
			where dname= #{dname}
		</if>
	</select>

	<!--查询id=1或者3的部门信息 where 去除多余的and或者or-->
	<select id="getIds" resultType="Dept">
		select
		<include refid="names"></include>
		from dept
		<!-- 使用if标签用来判断,条件成立才执行sql,不成就不执行-->
		<where>
			<if test=" id != null ">
				id =#{id}
			</if>
			or id =3
		</where>
	</select>

	<!--删除id 1,2,3的数据-->
	<select id="delId1">
		<!--delete from dept where id in(1,2,3),参数写死了,最好动态解析-->
		delete from dept where id in
		<!--
			foreach用来遍历,collection属性的值是固定值array list map里的key
			item相当于遍历得到的数据 separator是数据间的分隔符
			open是开始,close是结束
		-->
		<foreach collection="array" item="i" separator="," open="(" close=")">
			#{i}
		</foreach>
	</select>

</mapper>
6.5、单元测试
package cn.tedu;

import cn.tedu.pojo.Dept;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;


public class Test1 {
    @Test
    public void get() throws IOException {
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

        //开启会话,给参数true,自动提交事务
        SqlSession session = factory.openSession(true);//true:自动提交事务,默认是false

        //执行SQL
        List<Dept> list = session.selectList("DeptMapperNS.getAll");
        for (Dept d : list) {
            System.out.println(d);
        }
        //Mybatis的以及缓存:相同的SqlSession执行相同的SQL时会查缓存不会再次发起SQL了
        List<Dept> list2 = session.selectList("DeptMapperNS.getAll");
        for (Dept d : list2) {
            System.out.println(d);
        }

        //引入sql片段查询
        List<Dept> list3 = session.selectList("DeptMapperNS.getAll1");
        for (Dept d : list3) {
            System.out.println(d);
        }

        //查询name=java教研部 的部门表部门信息
        List<Dept> list4 =session.selectList("DeptMapperNS.getName","java教研部");
        for (Dept d : list4) {
            System.out.println(d);
        }

        //查询name=java教研部 的部门表部门信息 if判断
        List<Dept> list5 = session.selectList("DeptMapperNS.getName","java教研部");
        for (Dept d : list5) {
            System.out.println(d);

        }
        //查询null 的部门表部门信息 if判断
        List<Dept> list6 = session.selectList("DeptMapperNS.getName1",null);
        for (Dept d : list6) {
            System.out.println(d);

        }

        //id=1或者3的部门信息
        List<Dept> list7 = session.selectList("DeptMapperNS.getIds",19);
        for (Dept d : list7) {
            System.out.println(d);
        }

        //删除id 1,2,3的数据
        Integer[] arr = {1,2,3};
        session.delete("DeptMapperNS.delId1",arr);
        //

        /*开启会话,给参数true,自动提交事务
             SqlSession session = factory.openSession(true);
             session.commit();//增删改都需要提交事务,不然对数据库没有持久性的影响---就可以省略
        */
        System.out.println("删掉了");
    }
}

==Mybatis的以及缓存:相同的SqlSession执行相同的SQL时会查缓存不会再次发起SQL
增删改都需要提交事务,不然对数据库没有持久性的影响
Mybatis不会自动提交事务,需要手动提交:openSession(true)或者commit() ==

六、MyBatis:接口映射方式

1、概述

在上面的测试用例中,在调用session的方法的时候,都会传入要调用的SQL的namespace+id名称,这不是必须的。可以只传入id即可。但是,如果在mybatis的环境中有多个相同id的映射名称,就会报错。所以,一般情况下,调用方法最好还是使用namespace+id。但是,namespace+id的使用方式很容易报错,因为是string类型的,没有检查。所以,mybatis提供了一种非常好的设计方式来避免这种问题,即Mapper接口。

2、案例

2.1)maven工程结构

在这里插入图片描述

2.2)修改映射文件,把namespace的值改成接口的全路径,DeptMapper.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="cn.tedu.dao.DeptDao">
	<!--select标签表示要发起查询的SQL,
	id是SQL语句的唯一标识,
	resultType用来完成ORM,把表里的字段值 自动映射 类里的属性
	-->
	<!-- 提取sql片段 -->
	<sql id="names">
        id,dname,loc
    </sql>

	<!--静态查询dept表中所有的信息-->
	<!--resultType使用了别名,因为在核心配置文件里配过了 -->
	<select id="getAll1" resultType="Dept">
        select * from dept;
    </select>

	<!--动态查询dept表中所有的信息-->
	<select id="getAll" resultType="Dept">
		<!-- 引入标签前的代码:select * from dept-->
		<!--引入后-->
		/* include引入sql片段,refid指定sql片段的id值 */
		select
		<include refid="names"></include>
		from dept
	</select>

	<!--查询name=java教研部 的部门表部门信息 -->
	<select id="getName" resultType="Dept">
		select
		<include refid="names"></include>
		from dept
		where
		dname = #{dname}
	</select>

	<!--查询name=java教研部 的部门表部门信息 if判断-->
	<select id="getName1" resultType="Dept">
		select
		<include refid="names"></include>
		from dept
		<!-- 使用if标签用来判断,条件成立才执行sql,不成就不执行-->
		<if test=" dname != null ">
			where dname= #{dname}
		</if>
	</select>

	<!--查询id=1或者3的部门信息 where 去除多余的and或者or-->
	<select id="getIds" resultType="Dept">
		select
		<include refid="names"></include>
		from dept
		<!-- 使用if标签用来判断,条件成立才执行sql,不成就不执行-->
		<where>
			<if test=" id != null ">
				id =#{id}
			</if>
			or id =3
		</where>
	</select>

	<!--删除id 1,2,3的数据-->
	<select id="delId1">
		<!--delete from dept where id in(1,2,3),参数写死了,最好动态解析-->
		delete from dept where id in
		<!--
			foreach用来遍历,collection属性的值是固定值array list map里的key
			item相当于遍历得到的数据 separator是数据间的分隔符
			open是开始,close是结束
		-->
		<foreach collection="array" item="i" separator="," open="(" close=")">
			#{i}
		</foreach>
	</select>

</mapper>
2.3)修改核心配置文件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">

<!-- mybatis的核心配置文件 -->
<configuration>
    <!--用来设置别名 type是类的全路径 alisa是以后要使用的别名-->
    <typeAliases>
        <typeAlias type="cn.tedu.pojo.Dept" alias="Dept"></typeAlias>
    </typeAliases>

    <!--可以配置多个数据库连接的环境,使用default指定默认用哪个-->
    <environments default="test">
        <!--配置了具体连接数据库的参数-->
        <environment id="test">
            <!--使用的事务管理器-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源:就是制定了数据库连接时的参数-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdb?characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai" />
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入映射文件-->
    <mappers>
        <mapper resource="DeptMapper.xml"/>
    </mappers>
</configuration>
2.4)创建接口文件,DeptDao.java

接口文件的全路径 = Mapper.xml里namespace的值
接口中的方法名 = Mapper.xml里的SQL的id值
接口中的方法的返回值 = Mapper.xml里的SQL的resultType值

package cn.tedu.dao;
import cn.tedu.pojo.Dept;
import java.util.List;

public interface DeptDao {

	/**
	 * 获取所有
	 * @return 所有部门信息
	 */
	List<Dept> getAll();

	/**
	 * 根据名称获取部门信息
	 * @return 相关名字的部门信息
	 */
	List<Dept> getName(String name);
	List<Dept> getByIds(int[] id);
	void delId1(int[] id);
}
2.5)创建单元测试类,测试
package cn.tedu;

import cn.tedu.dao.DeptDao;
import cn.tedu.pojo.Dept;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.jupiter.api.Test;

import java.io.InputStream;
import java.util.List;

public class Test2 {
	@Test
	public void get() throws Exception{
		//加载核心配置文件
		InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

		//创建会话工厂
		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

		//开启会话,给参数true,自动提交事务
		SqlSession session = factory.openSession(true);//true:自动提交事务,默认是false

		//获取指定接口
		DeptDao dao = session.getMapper(DeptDao.class);

		//调用接口里的方法
		List<Dept> list = dao.getAll();
		for (Dept d : list) {
			System.out.println(d);
		}
		//根据名称获取部门信息
		List<Dept> list2 = dao.getName("开发");
		for (Dept dept : list2) {
			System.out.println(dept);
		}
	}

}

2.6)总结

在这里插入图片描述

七、ResultMap简单使用

1、概述

当数据库的字段名和对象的属性名 一致时,可以用简单属性resultType。

但是当数据库中的字段名称和对象中的属性名称 不 一致时,就需要resultMap属性。

2、案例

<?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="cn.tedu.mybatis.pojo.PersonMapper">
	<!-- 最强大对象resultMap,结果封装到哪个pojo对象,type就是谁 -->
	<resultMap type="Person" id="personRM">
		<!—单独处理 属性名  字段名不一致的 -->
		<result property="userName" column="user_name"/>
	</resultMap>
	<!-- 查询所有 -->
<select id="find"  resultMap="personRM">
SELECT id,user_name FROM person WHERE id=#{id}
</select>
</mapper>

八、自动匹配规范驼峰规则

数据库中我们习惯使用全大写,多个单词用下划线隔开,而po对象中,习惯使用java驼峰规则。那一个一个手工写resultMap字段,浪费开发时间,直接配置一下就可以了。

如:
数据库字段: is_man
Javabean属性: private Integer isMan
mapper配置不需要写字段与属性的配置,会自动映射
注意:主键需要单独写,其它字段就可以直接利用驼峰规则自动映射。

第一步:在sqlMapConfig.xml中配置settings:

<?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>
         <!--开启驼峰规则-->
		<setting name="mapUnderscoreToCamelCase" value="true" />
	</settings>
</configuration>

第二步:resultMap配置autoMapping=“true”

<resultMap type="cn.tedu.jk.domain.Contract" id="contractRM" autoMapping="true">
<!-- <id property="id" column="CONTRACT_ID"/> -- >
</resultMap>

八、扩展

1、JDBC和MyBatis的区别?

JDBC是java提供了一套专门用于和数据库对接的api,java.sql.*,其规范了如何和数据库进行对接,实现由各数据库厂商进行各自的实现和扩展。学习JDBC重点在学习如何使用其api。

MyBatis框架是轻量级封装了JDBC,我们已经看不到这些api,连接connection、语句preparedstatement、结果集ResultSet,而关注的是mybatis框架体系如何去使用,一旦写好,我们关注的是java对象。

2、XML和接口方式的区别?

MyBatis提供了两种操作数据库的方式,一种是通过xml映射文件,一种是通过java的接口类。按面向对象方式更加推荐接口方式,但如果复杂的多表映射,仍然需要使用xml映射文件的ResultMap方式实现。

接口只是假象,其底层仍然是通过xml实现,好不容易实现了一套方式,怎忍丢掉呢?可以做个测试就知道它底层怎么实现的?把xml中的sql删除,它就玩不转了。

3、接口方式怎么找到xml执行的?

SqlSession的getMapper方法找到类,通过反射可以获取到类的全路径(包名.类名),相加后就定位到某个xml的命名空间namespace,在根据调用的方法去找到xml中某个标签的id属性。从而实现价值接口,调用接口的方法而间接找到xml中的标签,通过解析xml获取这个标签的内容,从而获取到sql语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AimerDaniil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值