共计 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() |
创立向数据库发送 SQL 的Statement 对象 |
PreparedStatement prepareStatement(String sql) |
创立向数据库发送 预编译 SQL 的PreparedStatement 对象 |
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
代表 Jdbc
中SQL
语句的执行后果。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 会应用 JDBC 的getGeneratedKeys() 办法获取数据库外部产生的主键。 |
如下给出一个插入数据后获取插入数据的自增主键的示例。映射文件如下所示。
<?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
类的 bookName 和bookPrice属性与 book 表的 b_name 和b_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
语句。