MyBatis学习笔记(动力节点学习的)

2021/7/17 6:05:17

本文主要是介绍MyBatis学习笔记(动力节点学习的),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

MyBatis框架

http://www.bjpowernode.com学习的这个框架

什么是框架

框架定义

​ 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用骨架、模板。

​ 简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能。

​ 框架安全的,可复用的,不断升级的软件。

框架解决的问题

​ 框架要解决的最重要的一个问题是技术整合,在 J2EE 的 框架中,有着各种各样的技术,不同的应用,系统使用不同的技术解决问题。需要从 J2EE 中选择不同的技术,而技术自身的复杂性,有导致更大的风险。企业在开发软件项目时,主要目的是解决业务问题。 即要求企业负责技术本身,又要求解决业务问题。这是大多数企业不能完成的。框架把相关的技术融合在一起,企业开发可以集中在业务领域方面。

​ 另一个方面可以提供开发的效率。

常用框架介绍

MyBatis框架

​ MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过java 对象和 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。

​ MyBatis 本是 apache 的一个开源项目 iBatis, 2010 年这个项目由 apache software foundation 迁移到了 google code,并且改名为 MyBatis 。2013 年 11 月迁移到 Github。iBATIS 一词来源于“internet”和“abatis”的组合,是一个基于 Java 的持久层框架。iBATIS 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)

​ 当前,最新版本是 MyBatis 3.5.2 ,其发布时间是 2019年9月21日

Spring框架

​ Spring 框架为了解决软件开发的复杂性而创建的。Spring 使用的是基本的 JavaBean 来完成以前非常复杂的企业级开发。Spring 解决了业务对象,功能模块之间的耦合,不仅在 javase,web 中使用,大部分 Java 应用都可以从 Spring 中受益。

​ Spring 是一个轻量级控制反转(IOC)和面向切面(AOP)的容器。

SpringMVC框架

​ Spring MVC 属于 SpringFrameWork 3.0 版本加入的一个模块,为 Spring 框架提供了构建 Web 应用程序的能力。现在可以 Spring 框架提供的 SpringMVC 模块实现 web 应用开发,在 web 项目中可以无缝使用 Spring 和 Spring MVC 框架。

JDBC 编程

使用 JDBC 编程的回顾

public void findStudent() {
 	Connection conn = null;
 	Statement stmt = null;
 	ResultSet rs = null;
 	try {
 		//注册 mysql 驱动
 		Class.forName("com.mysql.jdbc.Driver");
 		//连接数据的基本信息 url ,username,password
 		String url = "jdbc:mysql://localhost:3306/springdb";
 		String username = "root";
 		String password = "123456";
 		//创建连接对象
 		conn = DriverManager.getConnection(url, username, password);
 		//保存查询结果
 		List<Student> stuList = new ArrayList<>();
 		//创建 Statement, 用来执行 sql 语句
 		stmt = conn.createStatement();
 		//执行查询,创建记录集,
 		rs = stmt.executeQuery("select * from student");
 		while (rs.next()) {
 			Student stu = new Student();
 			stu.setId(rs.getInt("id"));
			stu.setName(rs.getString("name"));
 			stu.setAge(rs.getInt("age"));
 			//从数据库取出数据转为 Student 对象,封装到 List 集合
 			stuList.add(stu);
 		}
 	} catch (Exception e) {
 		e.printStackTrace();
 	} finally {
 		try {
 			//关闭资源
 			if (rs != null){
 				rs.close()
            }
 			if (stmt != null) {
 				stmt.close();
 			}
 			if (conn != null) {
 				conn.close();
 			}
 	} catch (Exception e) {
 		e.printStackTrace();
 	} 
}

使用 JDBC 的缺陷

  1. 代码比较多,开发效率低

  2. 需要关注 Connection ,Statement, ResultSet 对象创建和销毁

  3. 对 ResultSet 查询的结果,需要自己封装为 List

  4. 重复的代码比较多些

  5. 业务代码和数据库的操作混在一起

MyBatis解决的主要问题

​ 减轻使用 JDBC 的复杂性,不用编写重复的创建 Connetion , Statement ; 不用编写关闭资源代码。直接使用 java 对象,表示结果数据。让开发者专注 SQL 的处理。 其他分心的工作由 MyBatis 代劳。

MyBatis 可以完成:

  1. 注册数据库的驱动,例如 Class.forName(“com.mysql.jdbc.Driver”))

  2. 创建 JDBC 中必须使用的 Connection , Statement, ResultSet 对象

  3. 从 xml 中获取 sql,并执行 sql 语句,把 ResultSet 结果转换 java 对象

List<Student> list = new ArrayLsit<>();
ResultSet rs = state.executeQuery(“select * from student”);
while(rs.next){
 	Student student = new Student();
 	student.setName(rs.getString(“name”));
 	student.setAge(rs.getInt(“age”));
 	list.add(student);
}

4.关闭资源

ResultSet.close() , Statement.close() , Conenection.close()

使用 Mybatis 准备(快速入门)

1.下载 mybatis

https://github.com/mybatis/mybatis-3/releases

image-20210716095931413

2.搭建 MyBatis 开发环境

数据库名 ssm ;表名 student

image-20210716000905559

INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1001,"孙尚香","sunshangxiang@qq.com",23);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1002,"凌统","lingtong@qq.com",42);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1003,"吕布","lvbu@qq.com",34);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1004,"张苞","zhangbao@qq.com",55);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1005,"赵云","zhaoyun@qq.com",43);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1006,"关羽","guanyu@qq.com",45);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1007,"马超","machao@qq.com",62);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1008,"黄忠","huangzhong@qq.com",22);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1009,"张飞","zhangfei@qq.com",65);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1010,"夏侯渊","xiahouyuan@qq.com",89);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1011,"邓艾","dengai@qq.com",34);
INSERT INTO student(`id`,`name`,`email`,`age`)VALUES(1012,"霍去病","huoqubing@qq.com",18);

3.创建 maven 工程

模板:

image-20210716001645754

工程坐标:

image-20210716002128333

4.加入maven坐标

pom.xml 加入 maven 坐标:

<dependencies>
    <!--Junit依赖-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
</dependencies>

说明:MyBatis的GAV坐标,可以在下载的MyBatis文件目录的说明文档中查看

5.加入 maven 插件

pom.xml 加入maven插件:

<build>
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties.xml 文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    
    <plugins>
 		<plugin>
 			<artifactId>maven-compiler-plugin</artifactId>
 			<version>3.1</version>
 			<configuration>
 				<source>1.8</source>
 				<target>1.8</target>
 			</configuration>
 		</plugin>
 	</plugins>
</build>

6.编写 Student 实体类

创建 com.atguigu.pojo包,创建实体类

package com.atguigu.pojo;
/**
 * 对应ssm数据库的student表
 */
public class Student {
    //属性名和列名一样
    private Integer id;
    private String name;
    private String email;
    private Integer age;
    //get/set/toString/constructor
    //代码略。。。
}

7.编写 Dao 接口 StudentDao

创建com.atguigu.dao包,创建StudentDao接口

package com.atguigu.dao;
import com.atguigu.pojo.Student;
import java.util.List;
/**
 * Dao接口
 */
public interface StudentDao {
    /**
     * 查询所有学生信息
     * @return 学生信息的List集合
     */
    public List<Student> selectStudents();
}

8.编写 Dao 接口 Mapper 映射文件 StudentDao.xml

要求:

  1. 在 dao 包中创建文件 StudentDao.xml

  2. 要 StudentDao.xml 文件名称和接口 StudentDao 一样,区分大小写的一样

<?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:必须有值,自定义的唯一字符串
 推荐使用:dao 接口的全限定名称
-->
<mapper namespace="com.atguigu.dao.StudentDao">
    <!--
        <select>: 查询数据, 标签中必须是 select 语句
        id: sql 语句的自定义名称,推荐使用 dao 接口中方法名称,
        使用名称表示要执行的 sql 语句
        resultType: 查询语句的返回结果数据类型,使用全限定类名
    -->
    <select id="selectStudents" resultType="com.atguigu.pojo.Student">
        <!--要执行的 sql 语句-->
        select id,name,email,age from student
    </select>
</mapper>

9.创建 MyBatis 主配置文件

项目 src/main 下创建 resources 目录,设置 resources 目录为 resources root

创建主配置文件:名称为 mybatis.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>
    <!--配置 mybatis 环境-->
    <environments default="mysql">
        <!--id:数据源的名称-->
        <environment id="mysql">
            <!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)-->
            <transactionManager type="JDBC"/>
            <!--数据源 dataSource:创建数据库 Connection 对象
            	type: POOLED 使用数据库的连接池
            -->
            <dataSource type="POOLED">
                <!--连接数据库的四个要素-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--告诉 mybatis 要执行的 sql 语句的位置-->
        <mapper resource="com/atguigu/dao/StudentDao.xml"/>
    </mappers>
</configuration>

支持中文的 url

jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8

10.创建测试类 MyBatisTest

@Test
    public void testStart() throws IOException {
        //访问mybatis读取student数据
        //1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
        String config = "MyBatis.xml";
        //2.读取配置文件
        InputStream is = Resources.getResourceAsStream(config);
        //3.创建了SqlSessionFactoryBuilder对象,目的是获取SqlSession
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //4.获取SqlSession,SqlSession能执行sql语句
        //SqlSession sqlSession = factory.openSession(true);//true表示设置为自动提交事务
        SqlSession sqlSession = factory.openSession();
        //5.【重要】指定要执行的sql语句的标识,sql映射文件中的namespace + "." + 标签的id值
        List<Student> studentList = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents");
        //mybatis默认不是自动提交事务的,所以在insert,update,delete后要手动提交事务(select语句不用)
        //sqlSession.commit();
        //6.循环输出查询结果
        for(Student student : studentList){
            System.out.println(student);
        }
        //7.关闭SqlSession,释放资源
        sqlSession.close();
    }

说明:

//5.【重要】指定要执行的sql语句的标识,sql映射文件中的namespace + "." + 标签的id值
List<Student> studentList = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents");

近似等价于jdbc中代码

Connection conn = 获取连接对象
String sql=” select id,name,email,age from student”
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();

11.配置日志功能

mybatis.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数

<settings>
 	<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
image-20210716095751137

配置日志文件,查询后控制台输出的信息:

G:\developer_tools\java1.8\jdk1.8\bin\java ...
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1136497418.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@43bd930a]
==>  Preparing: select id,name,email,age from student 
==> Parameters: 
<==    Columns: id, name, email, age
<==        Row: 1001, 孙尚香, sunshangxiang@qq.com, 23
<==        Row: 1002, 凌统, lingtong@qq.com, 42
<==        Row: 1003, 吕布, lvbu@qq.com, 34
<==        Row: 1004, 张苞, zhangbao@qq.com, 55
<==        Row: 1005, 赵云, zhaoyun@qq.com, 43
<==        Row: 1006, 关羽, guanyu@qq.com, 45
<==        Row: 1007, 马超, machao@qq.com, 62
<==        Row: 1008, 黄忠, huangzhong@qq.com, 22
<==        Row: 1009, 张飞, zhangfei@qq.com, 65
<==        Row: 1010, 夏侯渊, xiahouyuan@qq.com, 89
<==        Row: 1011, 邓艾, dengai@qq.com, 34
<==        Row: 1012, 霍去病, huoqubing@qq.com, 18
<==      Total: 12
Student{id=1001, name='孙尚香', email='sunshangxiang@qq.com', age=23}
Student{id=1002, name='凌统', email='lingtong@qq.com', age=42}
Student{id=1003, name='吕布', email='lvbu@qq.com', age=34}
Student{id=1004, name='张苞', email='zhangbao@qq.com', age=55}
Student{id=1005, name='赵云', email='zhaoyun@qq.com', age=43}
Student{id=1006, name='关羽', email='guanyu@qq.com', age=45}
Student{id=1007, name='马超', email='machao@qq.com', age=62}
Student{id=1008, name='黄忠', email='huangzhong@qq.com', age=22}
Student{id=1009, name='张飞', email='zhangfei@qq.com', age=65}
Student{id=1010, name='夏侯渊', email='xiahouyuan@qq.com', age=89}
Student{id=1011, name='邓艾', email='dengai@qq.com', age=34}
Student{id=1012, name='霍去病', email='huoqubing@qq.com', age=18}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@43bd930a]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@43bd930a]
Returned connection 1136497418 to pool.

Process finished with exit code 0

基本的CRUD

insert

(1)StudentDao 接口中增加方法

/**
* 添加一条学生信息
* @param student
* @return 影响的行数
*/
public int insertStudent(Student student);

(2)StudentDao.xml 加入 sql 语句

<!-- #{数据} 中的数据要与类中的属性保持一致-->
<insert id="insertStudent">
 	insert into student(id,name,email,age) values(#{id},#{name},#{email},#{age})
</insert>

(3)测试方法

	@Test
    public void testInsertStudent() throws IOException {
        //固定获取SqlSession的步骤
        String config = "MyBatis.xml";
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);     
        SqlSession sqlSession = factory.openSession();
        //创建保存数据的对象
        Student student = new Student(1013, "袁崇焕", "yuanchonghuan@qq.com", 32);
        //执行插入insert
        int result = sqlSession.insert("com.atguigu.dao.StudentDao.insertStudent",student);
        //提交事务(默认是不提交)
        sqlSession.commit();
        System.out.println("增加记录的行数:" + result);
        //关闭SqlSession
        sqlSession.close();
    }

执行测试方法后控制台输出信息:

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 110431793.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31]
==>  Preparing: INSERT INTO student (id,name,email,age)VALUES(?,?,?,?) 
==> Parameters: 1013(Integer), 袁崇焕(String), yuanchonghuan@qq.com(String), 32(Integer)
<==    Updates: 1
Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31]
增加记录的行数:1
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6950e31]
Returned connection 110431793 to pool.

update

(1)StudentDao接口中增加方法

/**
* 修改一条学生信息
* @param student
* @return 影响的行数
*/
public int updateStudent(Student student);

(2)StudentDao.xml加入sql语句

<!-- #{数据} 中的数据要与类中的属性保持一致-->
<update id="updateStudent">
        update student set age = #{age} where id = #{id}
</update>

(3)测试方法

	@Test
    public void testUpdateStudent() throws IOException {
        //固定获取SqlSession的步骤
        String config = "MyBatis.xml";
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = factory.openSession();
        //创建保存数据的对象
        Student student = new Student();
        student.setId(1013);
        student.setAge(99);
        //执行更新
        int result = sqlSession.update("com.atguigu.dao.StudentDao.updateStudent", student);
        //提交事务(默认是不提交)
        sqlSession.commit();
        System.out.println("修改记录的行数:" + result);
        //关闭SqlSession
        sqlSession.close();
    }

delete

(1)StudentDao 接口中增加方法

/**
* 删除一条学生信息
* @param id 需要删除学生的id
* @return 影响的行数
*/
public int deleteStudent(int id);

**(2)StudentDao.xml 加入 sql 语句 **

<!-- #{数据} 中的数据要与类中的属性保持一致-->
<delete id="deleteStudent" parameterType="java.lang.Integer">
        delete from student where id = #{id}
</delete>

(3)测试方法

	@Test
    public void testDeleteStudent() throws IOException {
        //获取SqlSession的固定步骤
        String config = "MyBatis.xml";
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = factory.openSession();
        //执行删除方法
        int result = sqlSession.delete("com.atguigu.dao.StudentDao.deleteStudent",1003);
        //提交事务(默认是不提交)
        sqlSession.commit();
        System.out.println("删除记录的行数:" + result);
        //关闭SqlSession
        sqlSession.close();
    }

MyBatis中使用的对象介绍

Resources

​ Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。

//1.定义mybatis主配置文件的名称, 从类路径的根开始(target/clasess)
String config = "MyBatis.xml";
//2.读取这个配置文件
InputStream is = Resources.getResourceAsStream(config);

SqlSessionFactoryBuilder

​ SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由 于SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。

//3.创建了SqlSessionFactoryBuilder对象,目的是获取SqlSession
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

SqlSessionFactory 接口

​ SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。

  • openSession(true):创建一个有自动提交功能的 SqlSession

  • openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交

  • openSession():同 openSession(false)

//4.获取SqlSession,SqlSession能执行sql语句
//SqlSession sqlSession = factory.openSession(true);//true表示设置为自动提交事务
SqlSession sqlSession = factory.openSession();

SqlSession 接口

​ SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束

​ SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。

//5.【重要】指定要执行的sql语句的标识,sql映射文件中的namespace + "." + 标签的id值
List<Student> studentList = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents");
//mybatis默认不是自动提交事务的,所以在insert,update,delete后要手动提交事务(select语句不用)
//sqlSession.commit();
//6.循环输出查询结果
for(Student student : studentList){
    System.out.println(student);
}
//7.关闭SqlSession,释放资源
sqlSession.close();

MyBatis使用CRUD操作优化

创建工具类MyBatisUtil获取SqlSession对象

package com.atguigu.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;
/**
 * 获取SqlSession的工具类
 */
public class MyBatisUtil {
    private static SqlSessionFactory factory = null;
    /**
     *因为SqlSessionFactory接口对象是一个重量级对象(系统开销大的对象)
     * 所以使用静态代码块创建一次SqlSessionFactory
     */
    static{
        try {
            //1.定义mybatis主配置文件的名称,从类路径的根开始(target/clasess)
            String config = "MyBatis.xml";
            //2.读取配置文件
            InputStream is = Resources.getResourceAsStream(config);
            //3.创建了SqlSessionFactoryBuilder对象,目的是获取SqlSession
             factory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            factory = null;
            e.printStackTrace();
        }
    }
    /**
     * 获取SqlSession对象
     * @return SqlSession对象,获取失败则返回null
     */
    public static SqlSession getSqlSession()  {
        if (factory != null){
            //4.获取SqlSession,SqlSession能执行sql语句
            SqlSession sqlSession = factory.openSession();
            return sqlSession;
        }
        return null;
    }
}

测试方法:

	@Test
    public void testMyBatisUtil(){
        //使用MyBatisUtil工具类获取SqlSession对象
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        System.out.println(sqlSession);
    }

执行方法后,控制台输出:

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
org.apache.ibatis.session.defaults.DefaultSqlSession@627551fb

传统 Dao 开发方式的分析

(1)创建StudentDao的实现类StudentDaoImpl,实现接口中的方法

package com.atguigu.dao.impl;

public class StudentDaoImpl implements StudentDao {
    @Override
    public List<Student> selectStudents() {
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        List<Student> students = sqlSession.selectList("com.atguigu.dao.StudentDao.selectStudents");
        sqlSession.close();
        return students;
    }  
}

(2)测试方法:

	private StudentDao studentDao = new StudentDaoImpl();
    @Test
    public void selectStudents() {
        List<Student> students = studentDao.selectStudents();
        for (Student student : students) {
            System.out.println(student);
        }
    }

​ 在前面例子中自定义 Dao 接口实现类时发现一个问题:Dao 的实现类其实并没有干什么实质性的工作,它仅仅就是通过 SqlSession 的相关 API 定位到映射文件 mapper 中相应 id 的 SQL 语句,真正对 DB 进行操作的工作其实是由框架通过 mapper 中的 SQL 完成的。

​ 所以,MyBatis 框架就抛开了 Dao 的实现类,直接定位到映射文件 mapper 中的相应 SQL 语句,对DB 进行操作。这种对 Dao 的实现方式称为 Mapper 的动态代理方式。

​ Mapper 动态代理方式无需程序员实现 Dao 接口。接口是由 MyBatis 结合映射文件自动生成的动态代理实现的。

Dao动态代理实现CRUD

(1)去掉StudentDao接口的实现类StudentDaoImpl,

(2)通过SqlSession的getMapper()方法获取StudentDaoImpl(原理为反射动态代理)

(3)getMapper()方法的参数为指定Dao接口类的class值

测试方法:

@Test
    public void testProxyDao(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        //用代理Dao类查询全部学生
        List<Student> students = dao.selectStudents();
        for (Student student : students) {
            System.out.println(student);
        }
        //用代理Dao类 插入方法
        Student student = new Student(1013, "袁崇焕", "yuanchonghuan@qq.com", 25);
        int insertStudent = dao.insertStudent(student);
        //手动提交事务
        sqlSession.commit();
        System.out.println("插入学生成功,影响行数:" + insertStudent);
    }

原理

动态代理

	/**
     * 查看动态代理源码入口
     */
    @Test
    public void testProxy(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        System.out.println(studentDao);
    }

执行方法后输出:

org.apache.ibatis.binding.MapperProxy@1f36e637

查看依赖jar包,进入源码查看...

深入理解参数

ParameterType

​ parameterType: 接口中方法参数的类型, 类型的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以推断出具体传入语句的参数,默认值为未设置(unset)。接口中方法的参数从 java 代码传入到mapper 文件的 sql 语句。

  • int 或 java.lang.Integer

  • hashmap 或 java.util.HashMap

  • list 或 java.util.ArrayList

  • student 或 com.bjpowernode.domain.Student

更多看 mybatis-3.5.1.pdf 的 15 页。

<select>,<insert>,<update>,<delete>都可以使用parameterType指定类型

例如:

<delete id="deleteStudent" parameterType="int">
 	delete from student where id=#{studentId}
</delete>

等同于

<delete id="deleteStudent" parameterType="java.lang.Integer">
 	delete from student where id=#{studentId}
</delete>

MyBatis参数传递

从 java 代码中把参数传递到 mapper.xml 文件。

一个简单参数

Dao 接口中方法的参数只有一个简单类型(java 基本类型和 String),占位符 #{ 任意字符 },和方法的参数名无关。

接口方法

	/**
     * 通过id 查询学生信息(一个简单参数)
     * @param id
     * @return
     */
    public Student selectById(int id);

mapper 文件:

<select id="selectById" resultType="com.atguigu.pojo.Student">
        select id,name,email,age from student where id = #{studentId}
</select>

测试方法

	/**
     * 通过id 查询学生信息(一个简单参数)
     */
    @Test
    public void testSelectById(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        Student student = dao.selectById(1005);
        System.out.println(student);
    }

多个参数-使用@Param

​ 当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入@Param(“自定义参数名”),

mapper 文件使用#{自定义参数名}

接口方法

	/**
     * 通过name 或 age 查询学生(多参数传递,使用@Param)
     * @param name
     * @param age
     * @return
     */
    public List<Student> selectMultiParam(@Param("studentName") String name,@Param("studentAge") int age);

mapper文件

<select id="selectMultiParam" resultType="com.atguigu.pojo.Student">
        select id,name,email,age from student where name = #{studentName} or age = #{studentAge}
</select>

测试方法

	/**
     * 通过name 或 age 查询学生(多参数传递,使用@Param)
     */
    @Test
    public void testSelectMultiParam(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Student> students = dao.selectMultiParam("吕布", 22);
        for (Student student : students) {
            System.out.println(student);
        }
    }

多个参数-使用对象

使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。

语法格式: #{ property,javaType=java中数据类型名,jdbcType=数据类型名称 }

javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }

mybatis-3.5.1.pdf 第 43 页 4.1.5.4 小节:

image-20210716175223295

创建保存参数值的对象 QueryParam

package com.atguigu.vo;
/**
 * 保存参数值的对象
 */
public class QueryParam {
    private String queryName;
    private int queryAge;
    //get,set
    ...

接口方法

	/**
     * 通过name或age查询学生(多个参数-使用对象)
     * @param queryParam 
     * @return 学生信息的List集合
     */
    public List<Student> selectMultiObject(QueryParam queryParam);

mapper文件

<select id="selectMultiObject" resultType="com.atguigu.pojo.Student">
        select id,name,email,age from student where name=#{queryName} or age = #{queryAge}
</select>

<!--不常用-->
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">
 	select id,name,email,age from student
 	where name=#{queryName,javaType=string,jdbcType=VARCHAR}
 	or age =#{queryAge,javaType=int,jdbcType=INTEGER}
</select>

测试方法

	/**
     * 通过name或age查询学生(多个参数-使用对象)
     */
    @Test
    public void testSelectMultiObject(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        QueryParam queryParam = new QueryParam();
        queryParam.setQueryName("孙尚香");
        queryParam.setQueryAge(44);
        List<Student> students = dao.selectMultiObject(queryParam);
        for (Student student : students) {
            System.out.println(student);
        }
    }

多个参数-按位置

参数位置从 0 开始, 引用参数语法 #{ arg 位置 } , 第一个参数是#{arg0}, 第二个是#{arg1}

注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。

接口方法

    /**
     * 通过name或age查询学生(多个参数-按位置)
     * @param name
     * @param age
     * @return 学生信息的List集合
     */
    public List<Student> selectByNameAndAge(String name,int age);	

mapper文件

    <select id="selectByNameAndAge" resultType="com.atguigu.pojo.Student">
        select id,name,email,age from student where name=#{arg0} or age =#{arg1}
    </select>

测试方法

	/**
     * 通过name或age查询学生(多个参数-按位置)
     */
    @Test
    public void testSelectByNameAndAge(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Student> students = dao.selectByNameAndAge("凌统", 22);
        for (Student student : students) {
            System.out.println(student);
        }
    }

多个参数-使用Map

Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,

Object 类型的值存储参数。 mapper 文件使用# { key } 引用参数值。

接口方法

   /**
     * 通过name或age查询学生(多个参数-使用Map)
     * @param map
     * @return
     */
    public List<Student> selectMultiMap(Map<String,Object> map);

mapper文件

     <select id="selectMultiMap" resultType="com.atguigu.pojo.Student">
        select id,name,email,age from student where name = #{myName} or age = #{myAge}
    </select>

测试方法

    /**
     * 通过name或age查询学生(多个参数-使用Map)
     */
    @Test
    public void testSelectMultiMap(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        Map<String,Object> map = new HashMap<>();
        map.put("myName","夏侯渊");// #{myName}
        map.put("myAge",22);// #{myAge}
        List<Student> students = dao.selectMultiMap(map);
        for (Student student : students) {
            System.out.println(student);
        }
    }

#和$的区别

# :占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句,

#{…}代替sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法。

$ :字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的

内容连接起来。主要用在替换表名,列名,不同列排序等操作。(有sql注入风险!)

封装 MyBatis 输出结果

resultType

resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType 和 resultMap,不能同时使用。

image-20210716182952455

1.简单类型

接口方法

     /**
     * 查询学生个数(简单类型返回值)
     * @return
     */
    public int countStudent();

mapper文件

    <select id="countStudent" resultType="int">
        select count(*) from student
    </select>

测试方法

    /**
     * 查询学生个数(简单类型返回值)
     */
    @Test
    public void testCountStudent(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        int countStudent = dao.countStudent();
        System.out.println("学生总人数:" + countStudent);
    }

2.对象类型

接口方法

    /**
     * 通过id查询学生信息(对象类型返回值)
     * @return
     */
    public Student selectById();  

mapper文件

    <select id="selectById" resultType="com.atguigu.pojo.Student">
        select id,name,email,age from student where id = #{studentId}
    </select>  

测试方法

    /**
     * 通过id 查询学生信息(一个简单参数)
     */
    @Test
    public void testSelectById(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        Student student = dao.selectById(1005);
        System.out.println(student);
    }

框架的处理:使用构造方法创建对象。调用 setXXX 给属性赋值。

  1. Student student = new Student();
  2. 调用列名对应的set方法
sql 语句列 java 对象方法
id setId( rs.getInt(“id”) )
name setName( rs.getString(“name”) )
email setEmail( rs.getString(“email”) )
age setAge( rs.getInt(“age”) )

注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。

image-20210716185900854

3.Map类型

sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map<Object,Object>。

注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。

接口方法

	/**
     * 通过id查询学生信息(返回值为Map类型)
     * @param id
     * @return
     */
    public Map<Object,Object> selectReturnMap(int id);

mapper文件

   <select id="selectReturnMap" resultType="java.util.HashMap">
        select id,name,email,age from student where id = #{studentId}
   </select>

测试方法

  	/**
     * 通过id查询学生信息(返回值为Map类型)
     */
    @Test
    public void testSelectReturnMap(){
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        Map<Object, Object> returnMap = dao.selectReturnMap(1001);
        System.out.println("查询结果为:" + returnMap);
    }

resultMap

resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。

常用在列名和 java 对象属性名不一样的情况。

使用方式:

1.先定义 resultMap,指定列名和属性的对应关系。

2.在

mybatis.xml 主配置文件定义别名:

第一种方式(定义单个类型的别名)

<!--定义别名-->
<typeAliases>
    <!--
        第一种方式:
        定义单个类型的别名
        type:自定义类型的全限定名称
        alias:别名(短小,容易记忆的)
    -->
    <typeAlias type="com.atguigu.pojo.Student" alias="stu" />
    <typeAlias type="com.atguigu.vo.ViewStudent" alias="vstu" />-->      
</typeAliases>

第二种方式(批量定义别名)

<!--定义别名-->
<typeAliases>
    <!--
        第二种方式
		批量定义别名,扫描整个包下的类,别名为类名(类名不区分大小写)
        <package> name:包名
    -->
    <package name="com.atguigu.pojo"/>
    <package name="com.atguigu.vo"/>
</typeAliases>

mappers(映射器)

(1)<mapper resource=" "/>(指定多个mapper文件)

使用相对于类路径的资源,从 classpath 路径查找文件

例如:

<mapper resource="com/atguigu/dao/StudentDao.xml" /> 
<mapper resource="com/atguigu/dao/OrderDao.xml" />

(2)<package name=" "/>

指定包下的所有 Dao 接口

例如:

<package name="com.atguigu.dao"/> 
<package name="com.atguigu.dao1"/> 
<package name="com.atguigu.dao2"/> 

注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中

→修改后的主配置文件

<?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>
    <properties resource="jdbc.properties" />
    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--定义别名-->
    <typeAliases>
        <!--
            第一种方式:
            可以指定一个类型一个自定义别名
            type:自定义类型的全限定名称
            alias:别名(短小,容易记忆的)
        -->
        <!--
        <typeAlias type="com.atguigu.pojo.Student" alias="stu" />
        <typeAlias type="com.atguigu.vo.ViewStudent" alias="vstu" />-->

        <!--
          第二种方式
          <package> name是包名, 这个包中的所有类,类名就是别名(类名不区分大小写)
        -->
        <package name="com.atguigu.pojo"/>
        <package name="com.atguigu.vo"/>
    </typeAliases>
    <!--配置 mybatis 环境-->
    <environments default="mysql">
        <!--id:数据源的名称-->
        <environment id="mysql">
            <!--配置事务类型:使用 JDBC 事务(使用 Connection 的提交和回滚)-->
            <transactionManager type="JDBC"/>
            <!--数据源 dataSource:创建数据库 Connection 对象
            type: POOLED 使用数据库的连接池
            -->
            <dataSource type="POOLED">
                <!--连接数据库的四个要素-->
                <!--使用 properties 文件: 语法 ${key}-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- sql mapper(sql映射文件)的位置(告诉 mybatis 要执行的 sql 语句的位置)-->
    <mappers>
        <!--第一种方式:指定多个mapper文件-->
        <!--
        <mapper resource="com/atguigu/dao/StudentDao.xml"/>
        <mapper resource="com/atguigu/dao/OrderDao.xml" />
        -->

        <!--
            第二种方式: 使用包名
            name: xml文件(mapper文件)所在的包名, 这个包中所有xml文件一次都能加载给mybatis
            使用package的要求:
             1. mapper文件名称需要和接口名称一样, 区分大小写
             2. mapper文件和dao接口需要在同一目录
        -->
        <package name="com.atguigu.dao" />
        <!--
            <package name="com.atguigu.dao2" />
            <package name="com.atguigu.dao3" />
       -->
    </mappers>
</configuration>

PageHelper

Mybatis 通用分页插件

https://github.com/pagehelper/Mybatis-PageHelper

PageHelper 支持多种数据库:

  1. Oracle

  2. Mysql

  3. MariaDB

  4. SQLite

  5. Hsqldb

  6. PostgreSQL

  7. DB2

  8. SqlServer(2005,2008)

  9. Informix

  10. H2

  11. SqlServer2012

  12. Derby

  13. Phoenix

基于 PageHelper 分页

实现步骤:

(1)maven坐标

<dependency>
 	<groupId>com.github.pagehelper</groupId>
 	<artifactId>pagehelper</artifactId>
 	<version>5.1.10</version>
</dependency>

(2)在mapper文件中加入plugin配置

之前加入

<!--配置PageHelper插件-->
<plugins>
 	<plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>

(3)PageHelper对象

​ 查询语句之前调用 PageHelper.startPage 静态方法。除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。

​ 在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个

方法后的第一个 MyBatis 查询方法会被进行分页。

@Test
public void testSelect() throws IOException {
	//获取第 1 页,3 条内容
	PageHelper.startPage(1,3);
 	List<Student> studentList = studentDao.selectStudents();
 	studentList.forEach( stu -> System.out.println(stu));
}


这篇关于MyBatis学习笔记(动力节点学习的)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程