关于数据库:Mybatis基础使用

3次阅读

共计 11259 个字符,预计需要花费 29 分钟才能阅读完成。

前言

Mybatis是一款 Java 长久层框架,外部将操作数据库须要的 Jdbc 相干代码进行了封装,同时能将 SQL 语句执行后果与 Pojo 间接进行映射。本篇文章将先对 Jdbc 进行学习,并在此基础上学习 Mybatis 的根底应用,无论是 Jdbc 还是 Mybatis,均是基于原生组件,不会与Spring 等框架进行整合。

Mybatis版本:3.5.6

注释

一. Jdbc 根底

Jdbc全称为 JavaDataBase Connectivity,即Java 数据库连贯,基于 Jdbc 能够获取数据库连贯并执行 SQL 语句,还能解决 SQL 语句的执行后果集。上面将对 Jdbc 的操作步骤进行介绍。

1. 加载数据库驱动

首先须要加载数据库驱动,这里以 Mysql 数据库驱动为例,如下所示。

Class.forName("com.mysql.jdbc.Driver");

2. 获取数据库连贯

而后须要获取数据库连贯,如下所示。

//url 用于标识数据库地位,即通知 Jdbc 连贯哪个数据库
String url = "jdbc:mysql://127.0.0.1:3306/test";
// 数据库用户名和明码
String username = "root";
String password = "root";
//Connection 是数据库编程中的一个重要对象,客户端与数据库的所有交互均依赖该对象
Connection connection = DriverManager.getConnection(url, username, password);

Connection对象局部重要办法如下所示。

办法 形容
Statement createStatement() 创立向数据库发送 SQLStatement对象
PreparedStatement prepareStatement(String sql) 创立向数据库发送 预编译 SQLPreparedStatement对象
commit() 提交事务
rollback() 回滚事务

3. 获取 Statement 对象

Statement对象用于向数据库发送 SQL 语句,获取形式如下所示。

Statement statement = connection.createStatement();

Statement对象的罕用办法如下所示。

办法 形容
ResultSet executeQuery(String sql) 向数据库发送查问 SQL 语句
int executeUpdate(String sql) 向数据库发送插入,更新或删除 SQL 语句
boolean execute(String sql) 向数据库发送任意 SQL 语句

应用 Statement 的查问示例如下所示。

Statement statement = connection.createStatement();
String sql = "SELECT * FROM worker";
ResultSet resultSet = statement.executeQuery(sql);

因为 Statement 的应用会引入 平安 效率 问题,所以通常 Jdbc 执行 SQL 语句是基于 PreparedStatement 对象。PreparedStatement继承于 Statement,应用PreparedStatement 的查问示例如下所示。

String sql = "SELECT * FROM worker WHERE sex = ?"
// 获取 PreparedStatement 对象时就须要传入 SQL 语句进行预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
// 设置参数,将第一个占位符替换为 "male"
preparedStatement.setString(1, "male");
// 执行查问,查问后果由 ResultSet 对象封装
ResultSet resultSet = preparedStatement.executeQuery();

相较于 Statement 对象,PreparedStatement对象执行效率更高(因为对 SQL 语句实现了预编译),并且能够避免 SQL 注入(因为获取 PreparedStatement 对象时就须要传入 SQL 语句进行预编译,此时不会产生用户输出数据扭转 SQL 语句构造的景象)。

4. 解决执行后果

ResultSet代表 JdbcSQL语句的执行后果。ResultSet封装执行后果时,采纳的是表格的形式,ResultSet对象保护了一个指向表格数据行的游标,初始状态时,游标在第 0 行(此时没有指向后果数据),调用 next() 办法后,游标会指向后果数据里的第一行数据,此时能够通过 ResultSet 对象来操作游标指向的这一行数据。ResultSet的罕用办法如下所示。

办法 形容
boolean next() 游标挪动到下一行
boolean previous() 游标挪动到上一行
boolean absolute(int row) 游标挪动到指定行
Object getObject(int columnIndex) 获取游标指向的行的第 columnIndex 列的任意类型数据
Object getObject(String columnLabel) 获取游标指向的行的 columnLabel 列的任意类型数据

5. 开释连贯

操作完数据库后,须要开释连贯,如下所示。

if (resultSet != null) {resultSet.close();
}
if (preparedStatement != null) {preparedStatement.close();
}
if (connection != null) {connection.close();
}

二. Mybatis 根底应用

1. Mybatis 构造

Mybatis的一个整体构造如下所示。

上图中呈现的 Mybatis 的组件的阐明如下。

组件 阐明
MybatisConfig.xml Mybatis的全局配置文件。配置 Mybatis 的运行环境(数据库连贯等)。
Mapper.xml 映射文件。映射文件中配置了操作数据库的 SQL 语句。
SqlSessionFactory 通过 MybatisConfig.xml 文件构建SqlSessionFactory,称为会话工厂。用于创立SqlSession
SqlSession 通过 SqlSessionFactory 创立 SqlSession,称为会话。操作数据库须要通过SqlSession 进行。
Executor SqlSession外部通过 Executor 执行数据库操作。
MappedStatement Executor通过 MappedStatement 在执行 SQL 语句前将输出的参数映射到 SQL 语句中,在执行 SQL 语句后将输入后果映射到设置的输入后果类型中。

2. 原始 Mybatis 应用

原始 Mybatis 的应用中,在引入 Mybatis 的包以及配置好 MybatisConfig.xml 之后,最重要的就是编写映射文件(Mapper.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="MyMapper">
    <select id="selectWorker" parameterType="java.lang.String" resultType="com.test.po.Worker">
        SELECT * FROM worker WHERE sex = #{sex}
    </select>
</mapper>

原始 Mybatis 执行映射文件时,首先须要获取 SqlSession,而后通过SqlSession 来调用映射文件。获取 SqlSession 的步骤如下所示。

// 指定全局配置文件
String resource = "MybatisConfig.xml";
// 读取全局配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 构建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();

SqlSession调用映射文件的示例如下所示。

// 第一个参数为:(映射文件的)命名空间 + "." +(映射文件的 SQL 语句的)id
// 第二个参数为:须要执行的 SQL 语句的参数值
List<Worker> workers = sqlSession.selectList("MyMapper.selectWorker", "male");

最初不要遗记敞开SqlSession,如下所示。

if (sqlSession != null) {sqlSession.close();
}

3. 动静代理 Mybatis 应用

动静代理 Mybatis 应用时,须要编写映射文件和映射接口,这里先给出映射文件,如下所示。

<mapper namespace="com.test.mapper.WorkerMapper">
    <select id="selectWorkerBySex" parameterType="java.lang.String" resultType="com.test.po.Worker">
        SELECT * FROM worker WHERE sex = #{sex}
    </select>
</mapper>

下面的映射文件中,<mapper>标签的 namespace 属性须要设置为与映射文件关联的映射接口的全限定名,<select>标签的 id 属性须要与映射接口定义的办法名统一,即映射接口定义的每一个办法须要和映射文件中的某一条 SQL 绝对应,Mybatis会为映射接口生成映射实例,通过调用映射实例的办法来实现对数据库的操作。下面的映射文件关联的映射接口如下所示。

public interface WorkerMapper {List<Worker> selectWorkerBySex(String sex);

}

动静代理 Mybatis 执行时,首先还是须要获取 SqlSession,而后通过SqlSession 来获取映射接口的实例。获取 SqlSession 的步骤如下所示。

// 指定全局配置文件
String resource = "MybatisConfig.xml";
// 读取全局配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 构建 SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 获取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();

获取映射接口的实例的步骤如下所示。

WorkerMapper workerMapper = sqlSession.getMapper(WorkerMapper.class);

获取映射接口的实例后,通过调用映射接口的实例的办法来执行 SQL 语句,如下所示。

List<Worker> list = workerMapper.selectWorkerBySex("male");

最初敞开SqlSession,如下所示。

if (sqlSession != null) {sqlSession.close();
}

三. Mybatis 标签语法

本节对映射文件中的罕用标签进行剖析,无非凡阐明时,默认 Mybatis 的应用是基于动静代理的形式。

1. <select> 标签

<select>标签示意查问 SQL 语句,标签罕用属性及阐明如下表所示。

属性 阐明
id 以后 namespace 下的惟一标识,要求 id 的值与映射接口中的办法名称统一。
parameterType 传入 SQL 语句的参数的类型的全限定名(能够省略,Mybatis能够本人推断出传入参数的类型)。
resultType SQL语句执行后返回的数据的类型的全限定名,如果返回的是汇合类型,则 resultType 为汇合存储的元素的类型的全限定名。
resultMap <resultMap> 标签配合应用。

如果须要传入多个参数,能够通过传入 Map 或者 Java Bean 来实现。上面将举两个例子来阐明 <select> 标签的应用。

例子 1:通过 Map 传入两个参数,别离为 age 和 salary,而后查问年龄大于 age 并且工资大于 salary 的所有工人数据。

映射文件如下所示。

<?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="com.test.mapper.WorkerMapper">
    <select id="selectAgeSalaryByMap" parameterType="java.util.Map" 
            resultType="com.test.po.Worker">
        SELECT * FROM worker WHERE age > #{age} and salary > #{salary}
    </select>
</mapper>

映射接口如下所示。

public interface WorkerMapper {List<Worker> selectAgeSalaryByMap(Map<String, Integer> map);

}

测试代码如下所示(省略 SqlSession 的获取)。

......
WorkerMapper workerMapper = sqlSession.getMapper(WorkerMapper.class);
Map<String, Integer> map = new HashMap<>();
map.put("age", 20);
map.put("salary", 10000);
List<Worker> workers = workerMapper.selectAgeSalaryByMap(map);
......

例子 2:通过 Java Bean 传入两个参数,别离为 age 和 salary,而后查问年龄大于 age 并且工资大于 salary 的所有工人数据。

Java Bean如下所示。

public class SelectInfo {

    private Integer age;
    private Integer salary;

    public Integer getAge() {return age;}

    public void setAge(Integer age) {this.age = age;}

    public Integer getSalary() {return salary;}

    public void setSalary(Integer salary) {this.salary = salary;}
    
}

映射文件如下所示。

<?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="com.test.mapper.WorkerMapper">
    <select id="selectAgeSalaryByBean" parameterType="com.test.po.SelectInfo" 
            resultType="com.test.po.Worker">
        SELECT * FROM worker WHERE age > #{age} and salary > #{salary}
    </select>
</mapper>

映射接口如下所示。

public interface WorkerMapper {List<Worker> selectAgeSalaryByBean(SelectInfo selectInfo);

}

测试代码如下所示(省略 SqlSession 的获取)。

......
WorkerMapper workerMapper = sqlSession.getMapper(WorkerMapper.class);
SelectInfo selectInfo = new SelectInfo();
selectInfo.setAge(20);
selectInfo.setSalary(10000);
List<Worker> workers = workerMapper.selectAgeSalaryByBean(selectInfo);
......

2. <insert> 标签

<insert>标签示意插入 SQL 语句,Mybatis执行完一条插入语句后,将返回一个整数示意其影响的行数。<insert>标签属性与 <select> 标签属性大部分雷同,下表给出不同的局部。

属性 阐明
keyProperty 设置为主键对应的属性时,能够获取插入操作后插入数据的主键值。
useGeneratedKeys 该属性为 true 时,Mybatis会应用 JDBCgetGeneratedKeys()办法获取数据库外部产生的主键。

如下给出一个插入数据后获取插入数据的自增主键的示例。映射文件如下所示。

<?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="com.test.mapper.WorkerMapper">
    <insert id="insertWorker" parameterType="com.test.po.Worker"
            keyProperty="id" useGeneratedKeys="true">
        INSERT INTO
        worker (name, sex, age, salary)
        VALUES
        (#{name}, #{sex}, #{age}, #{salary})
    </insert>
</mapper>

映射接口如下所示。

public interface WorkerMapper {Integer insertWorker(Worker worker);

}

Worker类构造如下所示。

public class Worker {

    private int id;
    private String name;
    private String sex;
    private int age;
    private int salary;

    public Worker() {}

    public Worker(String name, String sex,
                  int age, int salary) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.salary = salary;
    }

    // 省略 getter 和 setter
    ......

}

worker表的创立语句如下。

CREATE TABLE worker(id INT(11) PRIMARY KEY NOT NULL auto_increment,
    name VARCHAR(30) NOT NULL,
    sex VARCHAR(30) NOT NULL,
    age INT(11) NOT null,
    salary INT(11) NOT NULL
)

测试代码如下所示(省略 SqlSession 的获取)。

...
WorkerMapper workerMapper = sqlSession.getMapper(WorkerMapper.class);
Worker worker = new Worker("Lee", "male", 20, 10000);
Integer result = workerMapper.insertWorker(worker);
System.out.println(result + "pieces of data were inserted.");
System.out.println("The primary key of the inserted data is" + worker.getId());
...

3. <update> 和 <delete> 标签

这两个标签的属性与 <select><insert>标签的属性大体一致,并且在执行后会返回一个整数示意影响的记录数。

4. <resultMap> 标签

从数据库中查问出数据时,通常会将查问进去的数据映射成一个 Java Bean,然而如果数据库表的列名与Java Bean 的属性名不统一时,会无奈进行映射,此时须要应用 <resultMap> 标签来指定表列名和 Java Bean 属性名之间的映射关系。当初创立一张名为 book 的表,如下所示。

CREATE TABLE book(id INT(11) PRIMARY KEY auto_increment,
    b_name VARCHAR(255) NOT NULL,
    b_price INT(255) NOT NULL
)

创立一个 Book 类,用于与 book 表的查问后果进行映射,如下所示。

public class Book {

    private int id;
    private String bookName;
    private int bookPrice;

    // 省略 getter 和 setter
    ......

}

能够看到,Book类的 bookNamebookPrice属性与 book 表的 b_nameb_price列的名称不统一,从 book 表查问出的数据无奈映射到 Book 类上,此时须要应用 <resultMap> 标签来解决无奈映射的问题。映射文件如下所示。

<?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="com.test.mapper.BookMapper">
    <resultMap id="bookResultMap" type="com.test.po.Book">
        <result column="id" property="id"/>
        <result column="b_name" property="bookName"/>
        <result column="b_price" property="bookPrice"/>
    </resultMap>

    <select id="selectBookByName" parameterType="java.lang.String"
            resultMap="bookResultMap">
        SELECT * FROM book WHERE b_name=#{bookName}
    </select>
</mapper>

<resultMap>标签的 id 属性示意以后 namespace 下的惟一标识,能够通过 <resultMap> 标签的 id 属性来援用该 <resultMap><resultMap> 标签的 type 属性表映射类的全限定名,比方须要与 Book 类进行映射,则 type 字段应该为 Book 类的全限定名。<resultMap>标签下,一个 <result> 标签代表一对表列名和类属性名的映射,<result>标签的 column 属性为表的列名,<result>标签的 property 属性为类属性名。

下面映射文件对应的映射接口如下所示。

public interface BookMapper {List<Book> selectBookByName(String bookName);

}

测试代码如下所示(省略 SqlSession 的获取)。

......
BookMapper bookMapper = sqlSession.getMapper(BookMapper.class);
List<Book> mathBooks = bookMapper.selectBookByName("Math");
......

如果 Book 类中有一个属性为一个类,如下所示。

Book

public class Book {

    private int id;
    private String bookName;
    private int bookPrice;

    private BookStore bookStore;

    // 省略 getter 和 setter
    ......

}

BookStore

public class BookStore {

    private int bsId;
    private String bsName;

    // 省略 getter 和 setter
    ......

}

此时映射文件如下所示。

<?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="com.test.mapper.BookMapper">
    <resultMap id="bookResultMap" type="com.test.po.Book">
        <result column="id" property="id"/>
        <result column="b_name" property="bookName"/>
        <result column="b_price" property="bookPrice"/>

        <association property="bookStore" javaType="com.test.po.BookStore">
            <result column="bs_id" property="bsId"/>
            <result column="bs_name" property="bsName"/>
        </association>
    </resultMap>

    <select id="selectBookByName" parameterType="java.lang.String"
            resultMap="bookResultMap">
        SELECT * FROM book WHERE b_name=#{bookName}
    </select>
</mapper>

对于 Mybatis 标签的根底语法就剖析到这里,其中 <resultMap> 标签作为 Mybatis 中的性能最弱小标签,其所能实现的性能远不止上述介绍的性能,后续会独自就 <resultMap> 标签的应用进行深刻学习。

总结

本文对 JDBC 的根底应用和 Mybatis 的根底应用进行了剖析,并针对 Mybatis 的映射文件中的罕用标签的根底语法进行了介绍。通常 Mybatis 的应用须要编写映射文件和映射接口,且一个映射文件与一个映射接口绝对应,Mybatis会应用 JDK 动静代理为映射接口生成代理对象,当调用映射接口的办法时,调用申请会被代理对象拦挡,而后依据映射接口全限定名 + 办法名定位到相应的 MappedStatement 而后执行 SQL 语句。

正文完
 0