前言
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);//构建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 能够本人推断出传入参数的类型)。 |
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
语句。