MyBatis

一、MyBatis简介

1.1 框架概念

框架,就是软件的半成品,完成了软件开发过程中通用操作,码农只需很少或者不用加工就能实现特定的功能,从而简化开发人员在软件开发中的步骤,提高开发效率。

 1.2 常用框架

  • MVC框架:简化了Servlet的开发步骤,负责前端交换操作,常用:Struts2、SpringMVC        
  • 持久层框架:完成数据库操作的框架,简化了JDBC的开发步骤,常用:apache DBUtils、Hibernate、Spring JPA、MyBatis
  • 胶水框架:Spring

 SSM:Spring、SpringMVC、MyBatis

SSH:Spring、Struts2、Hibernate

1.3 MyBatis介绍

MyBatis是半自动ORM框架,灵活度高。

ORM(Object Relational Mapping)对象关系映射,将Java的一个对象与数据库表中一行记录一一对应。

ORM框架提供了实体类与数据表的映射关系,通过映射文件的配置,实现对象的持久化。

  • MyBatis的前身是iBatis,iBatis是Apache软件基金会提供的一个开源项目,2010年iBatis迁移到Google code,正式更名为MyBatis。
  • MyBatis特点:

(1)支持自定义SQL、存储过程;

(2)对原有的JDBC进行了封装,几乎消除了所有JDBC代码,让开发者只关注SQL本身;

(3)支持XML和注解配置方式自动完成ORM操作,实现结果映射(对象属性和数据表列之间);

二、MyBatis框架部署

框架部署,就是将框架引入到我们的项目中。

2.1 创建Maven项目

  • Java工程
  • Web工程

2.2 在项目中添加MyBatis依赖

(1)在pom.xml中添加依赖

  • mybatis
  • mysql driver
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>

2.3 创建MyBatis配置文件

  • 创建自定义模板,选中File->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>

</configuration>
  •  在resources中创建名为mybatis-config.xml文件
  • 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>
    
    <!-- 在environments配置数据库连接信息 -->
    <!-- 在environments标签中可以定义多个environment标签,每个environment标签可以定义一套连接配置 -->
    <!-- default属性,用来指定使用哪个environment标签 -->
    <environments default="mysql">
        
        <environment id="mysql">
            <!-- transactionManager标签用于配置数据库管理方式 -->
            <transactionManager type="JDBC">
                
            </transactionManager>
            <!-- dataSource 标签用于配置数据库连接信息 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/crud?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
        
    </environments>
</configuration>

三、MyBatis框架使用

案例:学生信息的数据库操作

3.1 创建数据库表

create table tb_students(
	sid int primary key auto_increment,
	stu_num char(5) not null unique,
	stu_name varchar(20) not null,
	stu_gender char(2) not null,
	stu_age int not null
);

3.2 创建实体类

package com.xiaochen.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Student {
    private int stuId;
    private String stuNum;
    private String stuName;
    private String stuGender;
    private int stuAge;
}

3.3 创建DAO接口,定义操作方法

package com.xiaochen.dao;

import com.xiaochen.pojo.Student;

public interface StudentDAO {

    public int insertStudent(Student student);
    public int deleteStudent(String stuNum);
}

3.4 创建DAO接口的映射文件

  • 在resources目录下,新建名为mappers文件夹
  • 在mappers中新建名为StudentMapper.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">
<mapper namespace="">

</mapper>
  • 在映射文件中对DAO中定义的方法进行实现:
<?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文件相当于DAO接口的实现类,namespace属性指定实现DAO接口的权限定名 -->
<mapper namespace="com.xiaochen.dao.StudentDAO">
    <!-- id代表调用哪个方法 -->
    <insert id="insertStudent">
        insert into tb_students(stu_num,stu_name,stu_gender,stu_age)
        values(#{stuNum},#{stuName},#{stuGender},#{stuAge})
    </insert>

    <delete id="deleteStudent">
        delete from tb_students where stu_num=#{stuNum}
    </delete>
</mapper>

3.5 将映射文件添加到主配置文件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>

    <!-- 在environments配置数据库连接信息 -->
    <!-- 在environments标签中可以定义多个environment标签,每个environment标签可以定义一套连接配置 -->
    <!-- default属性,用来指定使用哪个environment标签 -->
    <environments default="mysql">

        <environment id="mysql">
            <!-- transactionManager标签用于配置数据库管理方式 -->
            <transactionManager type="JDBC">

            </transactionManager>
            <!-- dataSource 标签用于配置数据库连接信息 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/crud?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>

    </environments>

    <mappers>
        <mapper resource="mappers/StudentMapper.xml"/>
    </mappers>

</configuration>

四、单元测试

4.1 添加单元测试依赖

<!-- Junit -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

4.2 创建单元测试类

在被测试类名后面alt+insert---选择Test

public interface StudentDAO {

    public int insertStudent(Student student);
    public int deleteStudent(String stuNum);
}

import com.xiaochen.pojo.Student;
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 java.io.IOException;
import java.io.InputStream;

class StudentDAOTest {

    @org.junit.jupiter.api.Test
    void insertStudent() {

        try{
            //加载mybatis配置文件,从流中获取
            InputStream is= Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            //会话工厂
            SqlSessionFactory factory=builder.build(is);
            //会话连接
            SqlSession sqlSession=factory.openSession();
            //通过会话获取DAO对象
            StudentDAO studentDAO=sqlSession.getMapper(StudentDAO.class);

            //测试StudentDAO的方法
            int i=studentDAO.insertStudent(new Student(0,"10001","张三","男",21));
            //需要手动提交
            sqlSession.commit();
            System.out.println(i);
        } catch (IOException e){
            e.printStackTrace();
        }
    }

    @org.junit.jupiter.api.Test
    void deleteStudent() {
    }
}

五、MyBatis的增删改查操作

案例:学生信息的增删查改

5.1 添加操作

省略

5.2 删除操作

根据学号删除一个学生信息

  • 在StudentDAO定义删除方法 
package com.xiaochen.dao;

import com.xiaochen.pojo.Student;

public interface StudentDAO {

    public int insertStudent(Student student);
    public int deleteStudent(String stuNum);
}
  • 在StudentMapper.xml中对接口方法进行"实现"
<delete id="deleteStudent">
    delete from tb_students where stu_num=#{stuNum}
</delete>
  • 测试:在StudentDAO的测试类中测试方法
    @org.junit.jupiter.api.Test
    public void deleteStudent() {
        try {
            // 获取输入流
            InputStream read=Resources.getResourceAsStream("mybatis-config.xml");

            //SqlSessionFactoryBuilder
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();

            //SqlSessionFactory表示MyBatis的会话工厂
            SqlSessionFactory factory=builder.build(read);

            //SqlSession表示MyBatis与数据库之间的会话,通过工厂方法设计模式
            SqlSession sqlSession=factory.openSession();

            //通过SqlSession对象调用getMapper方法获取DAO接口对象
            StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);

            //System.out.println(studentDAO);
            int i=studentDAO.deleteStudent("10001");
            System.out.println(i);
            sqlSession.commit();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

 5.3 修改操作

public int updateStudent(Student student);
  • 在StudentMapper.xml中对接口方法进行"实现" 
    <update id="updateStudent">
        update tb_students set stu_name=#{stuName},stu_gender=#{stuGender},stu_age=#{stuAge}
        where stu_num=#{stuNum}
    </update>
  • 测试:在StudentDAO的测试类中测试方法
 public void UpdateStudent() {
        try {
            // 获取输入流
            InputStream read=Resources.getResourceAsStream("mybatis-config.xml");

            //SqlSessionFactoryBuilder
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();

            //SqlSessionFactory表示MyBatis的会话工厂
            SqlSessionFactory factory=builder.build(read);

            //SqlSession表示MyBatis与数据库之间的会话,通过工厂方法设计模式
            SqlSession sqlSession=factory.openSession();

            //通过SqlSession对象调用getMapper方法获取DAO接口对象
            StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);

            //System.out.println(studentDAO);
            int i=studentDAO.updateStudent(new Student(0,"10001","张三","女",21));
            assertEquals(1,i);
            sqlSession.commit();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

5.4 查询操作-查询所有

 public List<Student> listStudents();
  • 在StudentMapper.xml中对接口方法进行"实现" 
    <!-- resultType指定查询结果封装的对象实体类 -->
    <!-- resultSets指定当前操作返回的集合类型(可省略) -->
    <!--  sid stuId 代表映射关系 -->
<!--    <select id="listStudents" resultType="com.xiaochen.pojo.Student" resultSets="java.util.list">-->
<!--        select sid stuId,stu_num stuNum,stu_name stuName,stu_gender stuGender,stu_age stuAge-->
<!--        from tb_students-->
<!--    </select>-->
    <!-- 第二种映射关系,用的比较多 -->
    <!-- resultMap标签用于定义实体类与数据表的映射关系(ORM)-->
    <resultMap id="studentMap" type="com.xiaochen.pojo.Student">
        <id column="sid" property="stuId"/>
        <result column="stu_num" property="stuNum"/>
        <result column="stu_name" property="stuName"/>
        <result column="stu_gender" property="stuGender"/>
        <result column="stu_age" property="stuAge"/>
    </resultMap>
    <!-- resultMap 用于引用一个实体的映射关系,当配置了resultMap之后resultType就可以省略 -->
    <select id="listStudents" resultMap="studentMap">
        select sid,stu_num,stu_name,stu_gender,stu_age from tb_students
    </select>
  • 测试:在StudentDAO的测试类中测试方法
 public void SelectStudents(){
        try {
            // 获取输入流
            InputStream read=Resources.getResourceAsStream("mybatis-config.xml");

            //SqlSessionFactoryBuilder
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();

            //SqlSessionFactory表示MyBatis的会话工厂
            SqlSessionFactory factory=builder.build(read);

            //SqlSession表示MyBatis与数据库之间的会话,通过工厂方法设计模式
            SqlSession sqlSession=factory.openSession();

            //通过SqlSession对象调用getMapper方法获取DAO接口对象
            StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);

            List<Student> list=studentDAO.listStudents();
            //assertNotNull(list);
            for(Student student:list){
                System.out.println(student);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

5.5 查询操作-查询一条记录 

根据学号查询一个学生

  • 在StudentDAO接口中定义方法

public Student queryStudent(String stuNum);
  • 在StudentMapper.xml中对接口方法进行"实现" 
  <select id="queryStudent" resultMap="studentMap">
        select sid,stu_num,stu_name,stu_gender,stu_age from tb_students
        where stu_num=#{stuNum}
    </select>
  • 测试:在StudentDAO的测试类中测试方法

    @Test
    public void testQueryStudent(){
        try {
            InputStream read=Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            SqlSessionFactory factory=builder.build(read);
            SqlSession sqlSession=factory.openSession();
            StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);

            Student student=studentDAO.queryStudent("10001");
            System.out.println(student);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

5.6 查询操作-多条件查询

分页查询(参数 start,pageSize)

在MyBatis进行查询操作:

  1. 如果操作方法只有一个简单类型或者字符串类型的参数,在Mapper配置中可以直接通过#{key},key为任意字符串,包括自定义;
  2. 如果操作方法有一个对象类型的参数,在Mapper配置中可以直接通过#{attrName}获取对象的指定属性值,attrName必须是对象的属性。
  3. 如果操作方法有一个Map类型的参数,在Mapper配置中可以直接通过#{key}对应的value
  • 在StudentMapper.xml中对接口方法进行"实现"  
    <select id="listStudentsByPage" resultMap="studentMap">
        select sid,stu_num,stu_name,stu_gender,stu_age from tb_students
        limit #{start},#{pageSize}
    </select>

比如:

public List<Student> listStudentsByPage(HashMap<String,Integer> map);
  •  分页查询通过map类型
    @Test
    public void testListStudentByPage(){
        try {
            InputStream read=Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            SqlSessionFactory factory=builder.build(read);
            SqlSession sqlSession=factory.openSession();
            StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);

            HashMap<String,Integer> map=new HashMap<String,Integer>();
            map.put("start",1);
            map.put("pageSize",3);
            List<Student> Students=studentDAO.listStudentsByPage(map);
            for(Student student:Students) {
                System.out.println(student);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

通常情况下,采用参数的方式,

  • 在StudentDAO中定义操作方法,如果方法有多个参数,使用@param注解声明参数的别名,
 public List<Student> listStudentsByPage(@Param("start") int start,@Param("pageSize") int pageSize);
  • 在StudentMapper.xml配置sql时,使用#{别名}获取指定的参数
    <select id="listStudentsByPage" resultMap="studentMap">
        select sid,stu_num,stu_name,stu_gender,stu_age from tb_students
        limit #{start},#{pageSize}
    </select>
    <!-- limit #{arg0},#{arg1}或者limit #{param},#{param} -->

注意:如果DAO操作方法没有通过@param指定参数别名,在SQL中也可以通过arg0,arg1...或者param1,param2...获取参数

5.7 查询操作-查询总记录数

  • 定义方法
public int getCount();
  • 配置文件,通过resultType指定当前操作的返回类型为int,
    <select id="getCount" resultType="int">
        select count(1) from tb_students
    </select>
  • 单元测试
 @Test
    public void testGetCount(){
        try {
            InputStream read=Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            SqlSessionFactory factory=builder.build(read);
            SqlSession sqlSession=factory.openSession();
            StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);

            int count=studentDAO.getCount();
            System.out.println(count);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

5.8 添加操作回填生成的主键

  • 在StudengMapper.xml的添加操作标签-insert
    <!-- useGeneratedKeys设置添加操作是否需要回填生成的主键 -->
    <!-- keyProperty设置回填的主键值赋值到参数对象的哪个属性 -->
    <insert id="insertStudent" useGeneratedKeys="true" keyProperty="stuId">
        insert into tb_students(stu_num,stu_name,stu_gender,stu_age)
        values(#{stuNum},#{stuName},#{stuGender},#{stuAge})
    </insert>

六、MyBatis工具类封装

package com.xiaochen.utils;

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 java.io.IOException;
import java.io.InputStream;

/*
 * @ClassName: MyBatisUtil
 * @Author: XiaoChen
 * @Date: 2021/12/15 星期三 19:40
 */
public class MyBatisUtil {
    private static SqlSessionFactory factory;
    private static final ThreadLocal<SqlSession> local=new ThreadLocal<SqlSession>();
    static {//单例模式
        try {
            InputStream read= Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            factory=builder.build(read);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession() {
        //加载mybatis配置文件
        SqlSession sqlSession=local.get();
        if(sqlSession==null){
            sqlSession=factory.openSession();
            local.set(sqlSession);
        }
        return sqlSession;
    }

    public static <T extends Object> T getMapper(Class<T> c){
        SqlSession sqlSession=getSqlSession();
        return sqlSession.getMapper(c);
    }
}

七、事务管理

SqlSession对象

  • getMapper(DAO.class):获取Mapper(DAO接口的实例)
  • 事务管理

7.1 手动提交事务

  • sqlSession.commit( ):提交事务
  • sqlSession.rollback():事务回滚
    @Test
    public void insertStudent() {
        SqlSession sqlSession=MyBatisUtil.getSqlSession();
        //1.当获取sqlSession对象时,就默认开启了事务
        try {
            StudentDAO studentDAO = sqlSession.getMapper(StudentDAO.class);
            //测试StudentDAO的方法
            Student student = new Student(0, "10007", "小华", "男", 21);
            int i = studentDAO.insertStudent(student);
            //需要手动提交
            sqlSession.commit();
            System.out.println(student);
        }catch (Exception e){
            //当操作出现异常,调用rollback进行回滚
            sqlSession.rollback();
        }
    }

7.2 自动提交事务

通过SqlSessionFactory调用openSession方法获取SqlSession对象时,可以设置参数是否自动提交。如果参数设置为true,表示自动提交事务;设置为false或者不设置,表示手动提交。
sqlSession=factory.openSession(true);
    public static SqlSession getSqlSession(boolean isAutoCommit) {
        //加载mybatis配置文件
        SqlSession sqlSession=local.get();
        if(sqlSession==null){
            //通过SqlSessionFactory调用openSession方法获取SqlSession对象时,可以设置参数是否自动提交
            sqlSession=factory.openSession(isAutoCommit);
            local.set(sqlSession);
        }
        return sqlSession;
    }

    public static <T extends Object> T getMapper(Class<T> c){
        SqlSession sqlSession=getSqlSession(true);
        return sqlSession.getMapper(c);
    }

MyBatisUtil代码优化

package com.xiaochen.utils;

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 java.io.IOException;
import java.io.InputStream;

/*
 * @ClassName: MyBatisUtil
 * @Author: XiaoChen
 * @Date: 2021/12/15 星期三 19:40
 */
public class MyBatisUtil {
    private static SqlSessionFactory factory;
    private static final ThreadLocal<SqlSession> local=new ThreadLocal<SqlSession>();
    static {//单例模式
        try {
            InputStream read= Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
            factory=builder.build(read);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    private static SqlSession getSqlSession(boolean isAutoCommit) {
        //加载mybatis配置文件
        SqlSession sqlSession=local.get();
        if(sqlSession==null){
            //通过SqlSessionFactory调用openSession方法获取SqlSession对象时,可以设置参数是否自动提交
            sqlSession=factory.openSession(isAutoCommit);
            local.set(sqlSession);
        }
        return sqlSession;
    }
    //手动事务提交
    public static SqlSession getSqlSession(){
        return getSqlSession(false);
    }
    //自动事务提交
    public static <T extends Object> T getMapper(Class<T> c){
        SqlSession sqlSession=getSqlSession(true);
        return sqlSession.getMapper(c);
    }
}

八、MyBatis主配置文件

mybatis-config.xml是MyBatis框架的主配置文件,只要用于配置MyBatis数据源及属性

8.1 properties

用于设置键值对,或者加载属性文件

  • 在resources目录下创建jdbc.properties文件,配置键值对的如下:
mysql_driver=com.mysql.jdbc.Driver
mysql_url=jdbc:mysql://localhost:3306/crud?characterEncoding=utf-8
mysql_username=root
mysql_password=1234
  • mybatis-config.xml中通过properties标签引用jdbc.properties文件,引入之后,在配置enviroment时可以直接使用jdbc.properties的key获取对应的value。

 8.2 settings标签

    <!-- 设置mybatis属性 -->
    <settings>
        <!-- 启动二级缓存 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 启动延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

8.3 typeAliases标签

    <!-- typeAliases标签用于给实体类取别名,在映射文件中可以直接使用别名来替代实体类的全限定名 -->
    <typeAliases>
        <typeAlias type="com.xiaochen.pojo.Student" alias="Student"> </typeAlias>
        <typeAlias type="com.xiaochen.pojo.Book" alias="Book"> </typeAlias>
    </typeAliases>

8.4 plugins标签

    <!-- plugins标签用于配置MyBatis插件(例如分页插件) -->
    <plugins>
        <plugin interceptor=""></plugin>
    </plugins>

8.5 environments标签

  <!-- 在environments配置数据库连接信息 -->
    <!-- 在environments标签中可以定义多个environment标签,每个environment标签可以定义一套连接配置 -->
    <!-- default属性,用来指定使用哪个environment标签 -->
    <environments default="mysql">
        <!-- environment标签用于配置数据库连接信息 -->
        <environment id="mysql">
            <!-- transactionManager标签用于配置数据库管理方式
             type="JDBC" 可以进行事务的提交和回滚操作
             type="MANAGED" 依赖容器完成事务管理,本身不进行事务的提交和回滚操作
             -->
            <transactionManager type="JDBC"> </transactionManager>
            <!-- dataSource 标签用于配置数据库连接信息 -->
            <dataSource type="POOLED">
                <property name="driver" value="${mysql_driver}"/>
                <property name="url" value="${mysql_url}"/>
                <property name="username" value="${mysql_username}"/>
                <property name="password" value="${mysql_password}"/>
            </dataSource>
        </environment>

    </environments>

8.6 mappers标签

加载映射配置(映射文件、DAO注解)

   <!-- mappers标签用于载入映射文件 -->
    <mappers>
        <mapper resource="mappers/StudentMapper.xml"/>
    </mappers>

九、映射文件

 9.1 MyBatis Mapper初始化

省略

9.2 mapper根标签

mapper文件相当于DAO接口的实现类,namespace属性要指定指定实现DAO的全限定名

9.3 insert 标签

声明添加操作(sql:insert...)

常用属性:

  • id属性,绑定对应DAO接口中的方法
  • parameterType属性,用于指定接口中对应方法的参数类型(可省略)
  • useGeneratedKeys属性,设置添加操作是否需要回填生成的主键
  • keyProperty属性,指定回填的id设置到参数对象中的哪个属性
  • timeout属性,设置此操作的超时时间,如果不设置则一直等待

主键回填

    <insert id="insertStudent" useGeneratedKeys="true" keyProperty="stuId">
        insert into tb_students(stu_num,stu_name,stu_gender,stu_age)
        values(#{stuNum},#{stuName},#{stuGender},#{stuAge})
    </insert>

9.4 delete标签

声明删除操作

9.5 update标签

声明修改操作

9.6 select标签

声明查询操作

  • id属性,指定绑定方法的方法名
  • parameterType属性,设置参数类型
  • resultType属性,指定当前sql返回数据封装的对象类型(实体类)
  • resultMap属性,指定从数据表到实体类的字段和属性的对应关系
  • useCache属性,指定此查询操作是否需要缓存
  • timeout属性,设置超时时间

9.7 resultMap标签

    <!-- 第二种映射关系,用的比较多 -->
    <!-- resultMap标签用于定义实体类与数据表的映射关系(ORM)-->
    <resultMap id="studentMap" type="com.xiaochen.pojo.Student">
        <id column="sid" property="stuId"/>
        <result column="stu_num" property="stuNum"/>
        <result column="stu_name" property="stuName"/>
        <result column="stu_gender" property="stuGender"/>
        <result column="stu_age" property="stuAge"/>
    </resultMap>

9.8 cache标签

设置当前DAO进行数据库操作时的缓存属性设置

<cache type="" size="" readOnly="false"/>

9.9 sql/include标签

   <sql id="wanglao">sid,stu_num,stu_name,stu_gender,stu_age</sql>
    
    <!-- resultMap 用于引用一个实体的映射关系,当配置了resultMap之后resultType就可以省略 -->
    <select id="listStudents" resultMap="studentMap">
        select <include refid="wanglao"/> from tb_students
    </select>

十、分页插件

分页插件是一个独立于MyBatis框架之外的第三方插件

10.1 添加分页插件的依赖

        <!-- pagehelper分页插件 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.2.0</version>
        </dependency>

10.2 配置插件

在mybatis的主配置文件mybatis-config.xml中通过plugins标签进行配置

    <!-- plugins标签用于配置MyBatis插件(例如分页插件) -->
    <plugins>
       <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

10.3 分页实例

对学生信息进行分页

    @Test
    public void testListStudentByPage(){
        StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class);
        PageHelper.startPage(1,3);
        List<Student> students=studentDAO.listStudents();
        //PageInfo包含了数据以及信息
        PageInfo<Student> pageInfo=new PageInfo<Student>(students);

        List<Student> list=pageInfo.getList();
        for(Student student:list) {
            System.out.println(student);
        }
    }

带条件分页

查找女性的信息

public List<Student> listStudentsByGender(String gender);
 <select id="listStudentsByGender" resultMap="studentMap">
        select <include refid="wanglao"/> from tb_students where stu_gender=#{gender}
    </select>
    @Test
    public void testListStudentByPage(){
        StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class);
        PageHelper.startPage(1,3);
        List<Student> students=studentDAO.listStudentsByGender("女");
        //PageInfo包含了数据以及信息
        PageInfo<Student> pageInfo=new PageInfo<Student>(students);

        List<Student> list=pageInfo.getList();
        for(Student student:list) {
            System.out.println(student);
        }
    }

十一、关联映射

11.1 实体关系

实体--数据实体,实体关系指的是数据与数据之间的关系

例如:用户和角色、房屋和楼栋、订单和商品

实体关系分为以下四种:

(1)一对一关联

  • 公民和身份证、学生和学生证

数据表关系:

  • 主键关联(用户表主键和详情表主键相同时,表示匹配的数据)
用户基本信息表用户详情表
用户ID,账号,密码,姓名,最后登录时间详情ID,手机...
1.张三1.14432049984
2.王五2.17865436578
3.李四3.18909876543
  • 唯一外键关联
用户基本信息表用户详情表
用户ID,账号,密码,姓名,最后登录时间详情ID,手机...  uid(外键,唯一)
1.张三1.14432049984    2
2.王五2.17865436578    3
3.李四3.18909876543     1

(2)一对多关联、多对一关联

实例:

  • 一对多:班级和学生、类别和商品
  • 多对一:学生和班级、商品和类别

数据表关联:

  • 在多个一端添加外键和一的一端进行关联

(3)多对多关联

实例:

  • 用户和角色、角色和权限、房屋和业主、学生和社团、订单和商品

数据表关系:

  • 建立第三张关系表添加两个外键分别与两张表主键进行关联

用户(user_id)、用户角色(uid、rid)、角色(role_id)

11.2 创建项目,部署MyBatis框架

  • 创建web项目(maven)
   <!-- 添加web依赖 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
  • 部署MyBatis框架

(1)添加依赖

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>

(2)配置文件

(3)帮助类

package com.xcsh.utils;

/*
 * @ClassName: MyBatisUtil
 * @Author: XiaoChen
 * @Date: 2021/12/16 星期四 16:24
 */


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 java.io.IOException;
import java.io.InputStream;

public class MyBatisUtil {
    private static SqlSessionFactory factory;
    private static final ThreadLocal<SqlSession> local=new ThreadLocal<>();
    
    static {
        try {
            InputStream is=Resources.getResourceAsStream("mybatis-config.xml");
            factory=new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public static SqlSessionFactory getSqlSessionFactory(){
        return factory;
    }
    
    public static SqlSession getSqlSession(boolean isAutoCommit){
        SqlSession sqlSession=local.get();
        if(sqlSession==null){
            sqlSession=factory.openSession(isAutoCommit);
            local.set(sqlSession);
        }
        return sqlSession;
    }
    
    public static SqlSession getSqlSession(){
        return getSqlSession(false);
    }
    
    public static<T extends Object> T getMapper(Class<T> c){
        SqlSession sqlSession=getSqlSession(true);
        return sqlSession.getMapper(c);
    }
}

11.3 一对一关联

实例:用户--详情

(1)创建数据表

--用户信息表
create table users(
    user_id int primary key auto_increment,
    user_name varchar(20) not null unique,
    user_pwd varchar(20) not null,
    user_realname varchar(20) not null,
    user_img varchar(100) not null
);


--用户详情表
create table details(
    detail_id int primary key auto_increment,
    user_addr varchar(50) not null,
    user_tel char(11) not null,
    user_desc varchar(200),
    uid int not null unique
);

(2)创建实体类

  • User
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private int userId;
    private String userName;
    private String userPwd;
    private String userRealName;
    private String userImg;
}
  • Detail
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Detail {
    private int detailId;
    private String userAddr;
    private String userTel;
    private String userDesc;
    private int userId;
}

(3)添加操作(事务)

  • 测试代码

(4)关联查询

在查询用户的同时关联查询出与之对应的详情

  • 实体
UserDetail
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private int userId;
    private String userName;
    private String userPwd;
    private String userRealName;
    private String userImg;

    private Detail detail;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Detail {
    private int detailId;
    private String userAddr;
    private String userTel;
    private String userDesc;
    private int userId;
}

映射文件

  • 连接查询

  •  子查询

 11.4 一对多关联

 案例:班级-学生

1)创建数据表

-- 创建班级信息表
create table classes(
    cid int primary key auto_increment,
    cname varchar(30) not null unique,
    cdesc varchar(100)
);

-- 创建学生信息表
create table students(
    sid char(5) primary key,
    sname varchar(20) not null,
    sage int not null,
    scid int not null
);

2)创建实体类

ClazzStudent
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Clazz {
    private int classId;
    private String className;
    private String classDesc;

    private List<Student> stus;
    // 存储当前班级下的学生信息
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private String stuId;//学号
    private String stuName;
    private int stuAge;
    private int stuCid;//学生所在班级的id
}

3)关联查询

当查询一个班级的时候,要关联查询出这个班级下的所有学生

  • 连接查询

  • 子查询

  11.5 多对一关联

 实例:学生(n)—班级(1)

当查询一个学生的时候,关联查询这个学生所在的班级信息

1)创建实体类

StudentClazz
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private String stuId;//学号
    private String stuName;
    private int stuAge;
    private Clazz clazz;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Clazz {
    private int classId;
    private String className;
    private String classDesc;
}

2)关联查询

  • 连接查询
    <resultMap id="studentMap" type="Student">
        <id column="sid" property="stuId" />
        <result column="sname" property="stuName" />
        <result column="sage" property="stuAge" />
        <result column="cid" property="clazz.classId" />
        <result column="cname" property="clazz.className" />
        <result column="cdesc" property="clazz.classDesc" />
    </resultMap>
    <select id="queryStudentBySid" resultMap="studentMap">
        select sid,sname,sage,scid,cid,cname,cdesc
        from students s INNER JOIN classes c
        ON s.scid=c.cid
        where s.sid=#{sid}
    </select>
  • 子查询

 11.5 多对多关联

案例:学生(m)—课程(n)

1)创建数据表

-- 学生信息表(同上)

-- 课程信息表
create table courses(
    course_id int primary key auto_increment,
    course_name varchar(50) not null
);

-- 选课信息表/成绩表(学号、课程号、成绩)
create table grades(
    sid char(5) not null,
    cid int not null,
    score int not null
);

2)关联查询

  • 查询学生时,同时查询学生选择的课程
StudentCourse
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private String stuId;//学号
    private String stuName;
    private int stuAge;
    private List<Course> courses;//学生选择的课程
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Course {
    private int courseId;
    private String courseName;
}

  • 根据课程编号查询课程时,同时查询选择了这门课程的学生
StudentCourse
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Student {
    private String stuId;//学号
    private String stuName;
    private int stuAge;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Course {
    private int courseId;
    private String courseName;
    private List<Student> students;
}
  • 连接查询的映射配置
    <resultMap id="courseMap" type="Course">
        <id column="course_id" property="courseId" />
        <result column="course_name" property="courseName" />
        <collection property="students" ofType="Student">
            <result column="sid" property="stuId" />
            <result column="sname" property="stuName" />
            <result column="sage" property="stuAge" />
        </collection>
    </resultMap>
    <select id="queryCourseById" resultMap="courseMap">
        select course_id,course_name,s.sid,sname,s.sage
        from courses c INNER JOIN grades g INNER JOIN students s
        ON c.course_id=g.cid and g.sid=s.sid
        WHERE c.course_id=#{courseId}
    </select>
  • 子查询映射配置
    <!-- 根据课程id查询选择了这门课的学生信息 -->
    <resultMap id="studentMap2" type="Student">
        <id column="sid" property="stuId" />
        <result column="sname" property="stuName" />
        <result column="sage" property="stuAge" />
    </resultMap>
    <select id="queryStudentsByCourseId" resultMap="studentMap2">
        select s.sid,sname,sage from students s INNER JOIN grades g
        ON s.sid=g.sid where g.cid=#{courseId};
    </select>

 十二、动态SQL

交友网:珍爱网、百合网     筛选心仪对象—性别、年龄、城市、身高

  • 张三   性别:女    select * from members where gender='女'
  • 李四   性别:女   年龄:18-23   select * from members where gender='女' and age>=18 and age<=23
  • 王五   年龄   城市   select  *  from members where age>=18 and age<=23 and city='广州'

电商:淘宝、京东       筛选商品—羽毛球拍、品牌、价格

用户筛选条件不同,我们完成筛选执行的SQL也不一样,可以通过穷举来一一完成不同条件的筛选,但是这种思路过于繁琐和复杂,但mybatis提供了动态sql的配置方式来实现多条件查询。

12.1 什么是动态SQL?

  • 根据查询条件动态完成SQL的拼接

12.2 动态SQL使用案例

案例:心仪对象搜索

1)创建数据表

create table members(
    member_id int primary key auto_increment,
    member_nick varchar(20) not null unique,
    member_gender char(2) not null,
    member_age int not null,
    member_city varchar(30) not null
);

2)创建实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Member {
    private int memberId;
    private String memberNick;
    private String memberGender;
    private int memberAge;
    private String memberCity;
}

3)创建DAO接口

在DAO接口中定义一个多条件查询的方法

public interface MemberDAO {
    //多条件查询下,若查询条件不确定,可以直接使用hashmap作为参数
    public List<Member> searchMember(HashMap<String,Object> params);
}

4)映射配置文件

  • if标签

  •  where标签用法

  •  trim标签

可以添加前后缀

  • foreach标签

十三、模糊查询

案例:根据昵称查询会员信息(模糊匹配 like)

13.1 模糊查询实现

模糊查询需使用${}取值,与SQL进行拼接。在使用${}时,即使只有一个参数@Param注解声明参数key(非String对象参数可以不进行声明)

1)DAO

public interface MemberDAO {
    //根据昵称查询用户信息-模糊查询
    //方式一
    //public List<Member> searchMemberByNick(HashMap<String,Object> params);
    //方式二
    public List<Member> searchMemberByNick(@Param("keyWord") String keyWord);
}

2)映射配置文件

  • ${ }和#{ }的区别

${key}表示获取参数,先获取参数值并拼接到SQL语句中,再编译执行SQL语句,可能引起SQL注入问题;
#{key}表示获取参数,先完成SQL编译(预编译),再将获取的参数设置到SQL,能够避免SQL注入问题;
<!-- SQL注入就是参数的值导致SQL的原意发生改变 -->

 3)测试

    @Test
    public void testSearchMemberByNick() {
        //HashMap<String,Object> params=new HashMap<String,Object>();
        //params.put("keyWord","花");
        MemberDAO memberDAO=MyBatisUtil.getMapper(MemberDAO.class);
        //List<Member> members=memberDAO.searchMemberByNick(param);
        List<Member> members=memberDAO.searchMemberByNick("花");

        for(Member m:members){
            System.out.println(m);
        }
    }

十四、常用注解

14.1 接口类的注解

1)@Repository

  • @Repository 是 Spring 的注解,用于声明一个 Bean。@Repository单独使用没用。可以这样理解,注解放在接口上本来就没有意义,spring中在mapper接口上写一个@Repository注解,只是为了标识,要想真正是这个接口被扫描,必须使用@MapperScannerConfigurer
@Repository
public interface UserMapper {
    List<User> getAllUsers();
    int updateUserAgeById(Integer id);
}
<!-- 配置 Mapper 扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.xsbc.mapper"/>
</bean>

 这段配置会扫描com.xsbc.mapper包下所有的接口,然后创建各自的动态代理类。
与spring集成可分三个步骤:

  • 把java类对应的Mapper接口类纳入spring总的IOC容器;
  • 把Java类对应的XML命名空间添加到Mybatis中的Configuration类中的mapperRegistry(用于管理Mybatis的Mapper);
  • 使用spring中的IOC容器拓展FactoryBean获取到Mapper的实例。(第一步纳入spring只是接口);

2)@Mapper

  • @Mapper是mybatis自身带的注解。在spring程序中,mybatis需要找到对应的mapper,在编译时生成动态代理类,与数据库进行交互,这时需要用到@Mapper注解。
@Mapper
public interface UserMapper {
    List<User> getAllUsers();
    int updateUserAgeById(Integer id);
}
  • 但是有时候当我们有很多mapper接口时,就需要写很多@Mappe注解,这样很麻烦,有一种简便的配置化方法便是在启动类上使用@MapperScan注解,而不需要添加@Mapper注解。
@SpringBootApplication
@MapperScan("com.xsbc.mapper")
public class SpringbootMysqlRedisApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootMysqlRedisApplication.class, args);
    }
}

14.2 实体类注解

若使用Spring Data JPA方式,则需引入依赖!可以省略建表的流程

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
  • @Entity:标注用于实体类声明语句之前,指出该Java 类为实体类,将映射到指定的数据库表;
  • @Table:当实体类与其映射的数据库表名不同名时需要使用 @Table 标注说明,该标注与 @Entity 标注并列使用,置于实体类声明语句之前,可写于单独语句行,也可与声明语句同行。@Table 标注的常用选项是 name,用于指明数据库的表名 @Table标注还有一个两个选项 catalog 和 schema 用于设置表所属的数据库目录或模式,通常为数据库名;
  • @Id:标注用于声明一个实体类的属性映射为数据库的主键列。该属性通常置于属性声明语句之前,可与声明语句同行,也可写在单独行上。
  • @GeneratedValue:用于标注主键的生成策略,通过 strategy 属性指定。
  • @Column:当实体的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明,该属性通常置于实体的属性声明语句之前,还可与 @Id 标注一起使用。标注的常用属性是 name,用于设置映射数据库表的列名。此外,该标注还包含其它多个属性,如:unique 、nullable、length 等。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

路上的追梦人

您的鼓励就是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值