Mybatis-基础使用

前言 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-基础使用
文章图片

上图中出现的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)。这里给出一个映射文件如下所示。
SELECT * FROM worker WHERE sex = #{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();

SqlSession调用映射文件的示例如下所示。
//第一个参数为:(映射文件的)命名空间 + "." + (映射文件的SQL语句的)id //第二个参数为:需要执行的SQL语句的参数值 List workers = sqlSession.selectList("MyMapper.selectWorker", "male");

最后不要忘记关闭SqlSession,如下所示。
if (sqlSession != null) { sqlSession.close(); }

3. 动态代理Mybatis使用 动态代理Mybatis使用时,需要编写映射文件和映射接口,这里先给出映射文件,如下所示。
SELECT * FROM worker WHERE sex = #{sex}

上面的映射文件中,标签的namespace属性需要设置为与映射文件关联的映射接口的全限定名,标签的id属性需要与映射接口定义的方法名一致,即映射接口定义的每一个方法需要和映射文件中的某一条SQL相对应,Mybatis会为映射接口生成映射实例,通过调用映射实例的方法来完成对数据库的操作。上面的映射文件关联的映射接口如下所示。
public interface WorkerMapper {List 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 list = workerMapper.selectWorkerBySex("male");

最后关闭SqlSession,如下所示。
if (sqlSession != null) { sqlSession.close(); }

三. Mybatis标签语法
本节对映射文件中的常用标签进行分析,无特殊说明时,默认Mybatis的使用是基于动态代理的方式。
1. 标签 标签表示查询SQL语句,标签常用属性及说明如下表所示。
属性 说明
id 当前namespace下的唯一标识,要求id的值与映射接口中的方法名称一致。
parameterType 传入SQL语句的参数的类型的全限定名(可以省略,Mybatis可以自己推断出传入参数的类型)。
resultType SQL语句执行后返回的数据的类型的全限定名,如果返回的是集合类型,则resultType为集合存储的元素的类型的全限定名。
resultMap 标签配合使用。
如果需要传入多个参数,可以通过传入Map或者Java Bean来实现。下面将举两个例子来说明标签的使用。
例子1:通过Map传入两个参数,分别为age和salary,然后查询年龄大于age并且工资大于salary的所有工人数据。
映射文件如下所示。
SELECT * FROM worker WHERE age > #{age} and salary > #{salary}

映射接口如下所示。
public interface WorkerMapper {List selectAgeSalaryByMap(Map map); }

测试代码如下所示(省略SqlSession的获取)。
...... WorkerMapper workerMapper = sqlSession.getMapper(WorkerMapper.class); Map map = new HashMap<>(); map.put("age", 20); map.put("salary", 10000); List 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; }}

映射文件如下所示。
SELECT * FROM worker WHERE age > #{age} and salary > #{salary}

映射接口如下所示。
public interface WorkerMapper {List selectAgeSalaryByBean(SelectInfo selectInfo); }

测试代码如下所示(省略SqlSession的获取)。
...... WorkerMapper workerMapper = sqlSession.getMapper(WorkerMapper.class); SelectInfo selectInfo = new SelectInfo(); selectInfo.setAge(20); selectInfo.setSalary(10000); List workers = workerMapper.selectAgeSalaryByBean(selectInfo); ......

2. 标签 标签表示插入SQL语句,Mybatis执行完一条插入语句后,将返回一个整数表示其影响的行数。标签属性与标签属性大部分相同,下表给出不同的部分。
属性 说明
keyProperty 设置为主键对应的属性时,可以获取插入操作后插入数据的主键值。
useGeneratedKeys 该属性为true时,Mybatis会使用JDBCgetGeneratedKeys()方法获取数据库内部产生的主键。
如下给出一个插入数据后获取插入数据的自增主键的示例。映射文件如下所示。
INSERT INTO worker (name, sex, age, salary) VALUES (#{name}, #{sex}, #{age}, #{salary})

【Mybatis-基础使用】映射接口如下所示。
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. 标签 这两个标签的属性与标签的属性大体一致,并且在执行后会返回一个整数表示影响的记录数。
4. 标签 从数据库中查询出数据时,通常会将查询出来的数据映射成一个Java Bean,但是如果数据库表的列名与Java Bean的属性名不一致时,会无法进行映射,此时需要使用标签来指定表列名和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类上,此时需要使用标签来解决无法映射的问题。映射文件如下所示。
SELECT * FROM book WHERE b_name=#{bookName}

标签的id属性表示当前namespace下的唯一标识,可以通过标签的id属性来引用该标签的type属性表映射类的全限定名,比如需要与Book类进行映射,则type字段应该为Book类的全限定名。标签下,一个标签代表一对表列名和类属性名的映射,标签的column属性为表的列名,标签的property属性为类属性名。
上面映射文件对应的映射接口如下所示。
public interface BookMapper {List selectBookByName(String bookName); }

测试代码如下所示(省略SqlSession的获取)。
...... BookMapper bookMapper = sqlSession.getMapper(BookMapper.class); List 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 ......}

此时映射文件如下所示。
SELECT * FROM book WHERE b_name=#{bookName}

关于Mybatis标签的基础语法就分析到这里,其中标签作为Mybatis中的功能最强大标签,其所能实现的功能远不止上述介绍的功能,后续会单独就标签的使用进行深入学习。
总结 本文对JDBC的基础使用和Mybatis的基础使用进行了分析,并针对Mybatis的映射文件中的常用标签的基础语法进行了介绍。通常Mybatis的使用需要编写映射文件和映射接口,且一个映射文件与一个映射接口相对应,Mybatis会使用JDK动态代理为映射接口生成代理对象,当调用映射接口的方法时,调用请求会被代理对象拦截,然后根据映射接口全限定名+方法名定位到相应的MappedStatement然后执行SQL语句。

    推荐阅读