前言

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.xmlMybatis的全局配置文件。配置Mybatis的运行环境(数据库连贯等)。
Mapper.xml映射文件。映射文件中配置了操作数据库的SQL语句。
SqlSessionFactory通过MybatisConfig.xml文件构建SqlSessionFactory,称为会话工厂。用于创立SqlSession
SqlSession通过SqlSessionFactory创立SqlSession,称为会话。操作数据库须要通过SqlSession进行。
ExecutorSqlSession外部通过Executor执行数据库操作。
MappedStatementExecutor通过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);//构建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//获取SqlSessionSqlSession 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);//构建SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//获取SqlSessionSqlSession 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能够本人推断出传入参数的类型)。
resultTypeSQL语句执行后返回的数据的类型的全限定名,如果返回的是汇合类型,则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语句。