MyBatis
2017-10-03 12:40
113 查看
简介
MyBatis曾被称为iBatis.iBatis是apache的一个开源项目,2010年迁移到google code,并且改名为MyBatis。
MyBatis是一个支持普通SQL查询、存储过程和高级映射的优秀持久层框架。MyBatis消除了绝大部分的JDBC代码,简化了手工设置SQL参数,以及对结果集的检索进行了封装。 MyBatis可以使用简单的XML或注解的方式来配置映射,将POJO(普通的Java对象,实体对象)映射成数据库中的记录。
MyBatis
① 获取MyBatis驱动包官网http://blog.mybatis.org/或https://github.com/mybatis/mybatis-3/releases中下载MyBatis的资源文件mybatis-3.x.x.zip,解压后可得到如下文件:
文件名 | 简介 |
---|---|
mybatis-3.x.x.jar | MyBatis的类库 |
mybatis-3.x.x-javadoc.jar | Mybatis的API帮助文档 |
mybatis-3.x.x-sources.jar | Mybatis的源代码 |
mybatis-3.x.x.pdf | MyBatis的开发向导 |
③ 创建(或使用之前已有的)“学生表”,各字段及类型如下:
字段名 | 类型 | 字段名 | 类型 |
---|---|---|---|
stuNo | number | stuAge | number |
stuName | nvarchar2(50) | garName | nvarchar2(50) |
④ 创建与学生表对应的实体类,如下,
package org.lzy.entity; public class Student { //学号 private int stuNo; //姓名 private String stuName; //年龄 private int stuAge; //年级名称 private String graName; //省略无参、各种带参的构造方法 //省略setter、getter //为了方便的输出对象中的内容,重写toString()方法 @Override public String toString() { return "学号:"+this.stuNo+"\t姓名:"+this.stuName +"\t年龄:"+this.stuAge+"\t年级:"+this.graName; } }
⑤ 创建学生表与学生类的映射关系文件:
org/lzy/entity/studentMapper.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="org.lanqiao.entity.studentMapper"> <select id=" queryStudentByNo" parameterType="int" resultType="org.lzy.entity.Student"> select * from student where stuNo=#{stuNo} </select> </mapper>
ps:在SQL映射文件中,SQL语句的最后没有分号
⑥ 创建MyBatis的配置文件,如下,
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <!-- 配置数据库连接信息 --> <dataSource type="POOLED"> <property name="driver" value="oracle.jdbc.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:XE" /> <property name="username" value="system" /> <property name="password" value="sa" /> </dataSource> </environment> </environments> <!-- 在配置文件(conf.xml)中注册SQL映射文件(studentMapper.xml)--> <mappers> <mapper resource="org/lanqiao/entity/studentMapper.xml" /> </mappers> </configuration>
说明:配置文件以conf.xml以及映射文件studentMapper.xml中的头信息、约束、子元素等,不必我们自己手写。可以再之前的mybatis-3.x.x.pdf,此向导文件中就有MyBatis的配置以及映射模板,只需要复制粘贴,然后修改相关属性值即可。
⑦ 编写测试类:执行SQL映射文件中定义的select语句
package org.lzy.test; //省略import public class TestMyBatis { public static void main(String[] args) throws IOException { String resource = "conf.xml"; // 加载mybatis 的配置文件 Reader reader = Resources.getResourceAsReader(resource); // 创建sqlSession 的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); // 创建能够执行SQL映射文件中sql语句的sqlSession对象 SqlSession session = sessionFactory.openSession(); // 指定sql语句对应的标识字符串:namespace+id String statement = "org.lzy.entity.studentMapper" + ". queryStudentByNo "; // 执行查询,返回一个学号为32的Student对象 Student student = session.selectOne(statement, 32); System.out.println(student); session.close(); } }
测试类中,statement变量指向了SQL映射文件中id为getStudentByNo的select标签, 并通过SqlSession对象的selectOne()方法,将“32”传入该select标签中,最后select标签中的SQL语句通过#{stuNo}将“32”赋值给了stuNo。
整体思路
MyBatis应用程序根据XML配置文件(conf.xml)创建SqlSessionFactory,再由SqlSessionFactory创建一个SqlSession对象。SqlSession对象包含了执行SQL所需要的所有方法,可以直接运行映射的SQL语句,完成对数据的增删改查等操作。其中映射的SQL语句存放在一个SQL映射文件中(如studentMapper.xml),应用程序可以通过SQL映射文件中的namespace+id找到对应的SQL语句。其中,SqlSession对象的常用方法如下:
方法 | 简介 |
---|---|
int insert(String statement, Object parameter) | 执行数据库的“增加”操作。如果SQL语句中没有参数,可以使用重载方法int insert(String statement)。返回值表示实际增加了几条数据。 |
int delete(String statement,Object parameter) | 执行数据库的“删除”操作。如果SQL语句中没有参数,可以使用重载方法int delete(String statement)。返回值表示实际删除了几条数据。 |
int update(String tatement, Object parameter) | 执行数据库的“修改”操作。如果SQL语句中没有参数,可以使用重载方法 int delete(String statement)。返回值表示实际修改了几条数据。 |
T selectOne(String statement,Object parameter); | 执行数据库中的“查询单个结果集”操作。如果SQL语句中没有参数,可以使用重载方法 T selectOne(String statement)。返回值表示查询到的结果,返回值类型通过SQL映射文件中的resultType属性指定。 |
List selectList(String statement, Object parameter); | 执行数据库中的“查询多行结果(结果集)”操作,如select * from student。如果SQL语句中没有参数,可以使用重载方法 List selectList(String statement)。返回值表示查询结果的集合对象,集合元素的类型通过SQL映射文件中的resultType属性指定。 |
void commit() | 事务的提交语句,会提交数据库的连接。需要注意的是,在执行增删改(insert()、delete()、update())命令后,必须执行commit()提交事务,否则数据库表中的数据不会发生任何变化。 |
statement:代表即将执行的sql语句,该sql语句是由sql映射文件中的namespace和标签元素的id值指定。
paramter:sql语句的参数值,参数类型通过SQL映射文件中的parameterType属性指定,并通过“#{}”取得。如果参数是简单类型(基本数据类型或String类型),直接使用“#{参数名}”取得;如果参数是对象类型,则需要使用“#{对象的属性名}”来获取。
MyBatis配置文件
官方MyBatis配置文件conf.xml模板<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml" /> </mappers> </configuration>
(1)多环境配置
default:指定默认environment的id值
environments:MyBatis允许配置多种不同的数据库环境,如开发环境、测试环境、工作环境等。因此在MyBatis中,我们可以使用相同的SQL映射来操作不同的数据库。但要注意,虽然允许配置多种不同的环境,但在使用时,environments只能选择唯一的一个环境,即通过environments元素的default属性来指定默认使用的environment的id值。这样可以方便开发者快速的在不同数据库环境之间切换。此外,每个数据库环境(environment元素),在程序中对应着一个SqlSessionFactory对象。
之前在测试类TesMyBatis.java中,通过配置文件(conf.xml)创建的SqlSessionFactory对象,就是根据数据库环境environment元素的内容产生的。具体代码如下:
String resource = "conf.xml"; // 加载mybatis 的配置文件 Reader reader = Resources.getResourceAsReader(resource); // 创建sqlSession 的工厂 SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
以上,是根据environments元素中default属性指定的数据库环境而产生的SqlSessionFactory对象。我们也可以在Java代码中显示的指定数据库环境,如下:
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader,"development");
即通过build()方法的第二个参数,将数据库的环境指定为id值为”development”所代表的environment。
(2)具体环境配置
environments的子元素,表示每一个具体的数据库环境。
id:数据库环境的id值
(3)事务管理器
<transactionManager type="JDBC" />
type: 指定事务管理器类型。在MyBatis中有两种事务管理器类型,JDBC和MANAGED
类型 | 简介 |
---|---|
JDBC | 使 102c0 用JDBC的提交和回滚来管理事务,即利用java.sql.Connection对象完成对事务的提交(commit())、回滚(rollback())、关闭(close())等 |
MANAGED | MyBatis自身不会去管理事务,而是把事务交给容器托管(比如Spring、JBOSS、Weblogic容器)。默认情况会关闭连接,若不想关闭则需要如下配置:<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager> |
<dataSource type="POOLED">
type: 指定数据源类型
MyBatis中有三种数据源类型,UNPOOLED、 POOLED和JNDI:
① UNPOOLED :每次被请求时简单打开和关闭连接,需要配置的以下属性:
属性名 | 简介 |
---|---|
driver | JDBC驱动的Java全类名 |
url | 数据库的JDBC URL地址 |
username | 登陆数据库的用户名 |
password | 登陆数据库的密码 |
defaultTransactionIsolationLevel | 默认的连接事务隔离级别 |
③ JNDI :从tomcat等容器中获取数据源
(5)映射文件
<mappers> <mapper resource="org/mybatis/example/BlogMapper.xml" /> </mappers>
mappers:用于配置SQL映射文件
mapper的resource属性:SQL映射文件(XxxMapper.java)的相对路径。
SQL映射文件
SQL映射文件(XxxMapper.java)基础模板如下:<?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="{namespace }"> <select id="{id}" parameterType="{ptype}" resultType="${rtype}"> SQL语句,例如:select * from student where stuNo=#{stuNo} </select> </mapper>
(1)命名空间
<mapper namespace="{namespace }">
给此映射文件设置一个命名空间,程序需要根据命名空间,找到某一个具体的映射文件。
(2)查询标签
<select id="{id}" parameterType="{ptype}" resultType="{rtype}"> SQL语句,例如:select * from student where stuNo=#{stuNo} </select>
id:唯一标识符,程序可以通过“命名空间+唯一标识符”(即namespace+id)来定位此select标签中的SQL语句。
parameterType:传入“SQL语句”中的参数类型。例如,SQL语句中“stuNo=#{stuNo}”表示需要传入一个int型的stuNo,就可以通过parameterType=”int”将输入参数的类型设置为int。
resultType : SQL语句的返回类型。例如,“select * from student …”返回的是一个学生的全部信息,可以用学生对象来保存,所以返回类型可以是Student类型,即resultType=”org.lzy.entity.Student”
使用MyBatis实现CRUD
CRUD是指create、read、upadate和delete。SQL映射文件:org/lzy/entity/studentMapper.xml
<mapper namespace="org.lzy.entity.studentMapper"> <!-- 增加一个学生 --> <insert id="addStudent" parameterType="org.lzy.entity.Student"> insert into student(stuNo,stuName,stuAge,graName) values(#{stuNo},#{stuName},#{stuAge},#{graName}) </insert> <!-- 根据学号,删除一个学生 --> <delete id="deleteStudentByNo" parameterType="int"> delete from student where stuNo=#{stuNo} </delete> <!-- 根据学号,修改学生信息 --> <update id="updateStudentByNo" parameterType="org.lzy.entity.Student"> update student set stuName=#{stuName},stuAge=#{stuAge}, graName=#{graName} where stuNo=#{stuNo} </update> <!-- 根据学号,查询一个学生 --> <select id=" queryStudentByNo " parameterType="int" resultType="org.lzy.Student"> select * from student where stuNo=#{stuNo} </select> <!-- 查询全部学生 --> <select id=" getAllStudents " resultType="org.lzy.entity.Student"> select * from student </select> </mapper>
测试类org.lzy.test.TestMyBatis.java
public class TestMyBatis { // 增加一个学生 public static void testAdd() throws IOException { … // 指定sql语句对应的标识字符串:namespace+id String statement = "org.lzy.entity.studentMapper" + ".addStudent"; Student stu = new Student(7, "路人甲", 22, "一年级"); session.insert(statement, stu); session.commit(); session.close(); } // 根据学号,删除一个学生 public static void testDeleteByNo() throws IOException { … String statement = "org.lzy.entity.studentMapper" + ".deleteStudentByNo"; session.delete(statement, 7); session.commit(); session.close(); } // 根据学号,修改学生信息 public static void testUpdate() throws IOException { … String statement = "org.lzy.entity.studentMapper" + ".updateStudentByNo"; Student stu = new Student(7, "路人乙", 33, "二年级"); session.update(statement, stu); session.commit(); session.close(); } // 根据学号查询一个学生 public static void testQueryStudentByNo () throws IOException { … String statement = "org.lzy.entity.studentMapper" + ".queryStudentByNo "; // 执行查询,返回一个学号为32的Student对象 Student student = session.selectOne(statement, 32); System.out.println(student); session.close(); } // 查询全部学生 public static void testQueryAll() throws IOException { String statement = "org.lzy.entity.studentMapper" + ".queryAllStudents"; // 执行查询,返回一个学号为32的Student对象 List<Student> students = session.selectList(statement); System.out.println(students); session.close(); } public static void main(String[] args) throws IOException { testQueryStudentByNo ();//根据学号,查询一个学生 testAdd();//增加一个学生 testUpdate();//根据学号,修改一个学生 testDeleteByNo();//根据学号,删除一个学生 testQueryAll();//查询全部学生 } }
ps:在执行增insert()、删delete()、改update()操作后,必须再执行commit()方法进行数据库提交,否则不会对数据库表中的数据产生影响。
使用Mapper动态代理优化
有一条软件设计范式称为“约定优于配置”,就是说如果有一些值没被配置的话,那么程序就会使用默认值(即“约定”)。换句话说,如果能按照“约定”去开发程序,就不需要配置了。我们之前开发的“MyBatisDemo”项目,在测试类(TestMyBatis.java)里,每执行一个数据库操作(增、删、改、查),都必须通过statement变量来指向SQL映射文件(studentMapper.xml)中某一个标签的id值(即通过namespace+id的方式指定,例如用String statement = “org.lanqiao.entity.studentMapper” + “.addStudent”来指定“增加”所需要的SQL语句)。可以发现,这种使用硬编码的方式来指定SQL语句,开发起来比较繁琐,因此我们可以使用“约定优于配置”来简化:使用“约定”来省略statement变量的配置。具体实现步骤如下:
(1)在之前的“MyBatisDemo”项目上二次开发。其中,学生表、学生实体类(Student.java)都与之前的完全一样。
(2)新建接口,在接口中定义操作数据库的方法,并给方法增加一些“约定”。其中,“约定”需要参照SQL配置文件(studentMapper.xml)中的各个标签(如
<select>),如下:
<!-- 根据学号,查询一个学生 --> <select id=" queryStudentByNo" parameterType="int" resultType="org.lzy.entity.Student"> select * from student where stuNo=#{stuNo} </select>
接口中方法的具体“约定”:
① 方法名和SQL配置文件(studentMapper.xml)中相关方法的id值相同。例如,SQL配置文件中“查询一个学生”的标签的id值是“queryStudentByNo”,那么在接口中“查询一个学生”的方法名就也必须是queryStudentByNo ()。
②方法的输入参数类型,和SQL配置文件中“parameterType”的类型相同。例如,SQL配置文件中“查询一个学生”的“parameterType”类型是int,则在接口中“查询一个学生”方法的输入参数类型就必须是int,即getStudentByNo(int stuNo)。特殊情况:如果SQL配置文件中不存在“parameterType”,则表示是一个无参方法。
③方法的返回值类型,和SQL配置文件中“resultType”的类型相同。例如,SQL配置文件中“查询一个学生”的“resultType”类型是“org.lanqiao.entity.Student”,则在接口中“查询一个学生”方法的返回值类型就必须是“org.lzy.entity.Student(或简写为Student)”,即Student getStudentByNo(int stuNo){ … }。
特殊情况:
①如果SQL配置文件中不存在“resultType”,则表示是方法的返回值为void。
②如果方法的返回值是一个集合类型(例如,返回类型是List
<Student>),但在SQL配置文件中的“resultType”却不能集合类型,而应该是集合中的元素类型(例如,配置文件中要使用resultType=”org.lzy.entity.Student“来表示返回值类型List
<Student>)。
有了上述三条“约定”,MyBatis就能将接口中的方法和数据库标签(如、等)一一对应起来,而不再需要使用statement变量来指定.
org.lzy.mapper.IStudentMapper.java
package org.lzy.maper; import java.util.List; import org.lzy.entity.Student; public interface IStudentMapper { //按照“约定”编写的“根据学号,查询一个学生”的接口方法 public abstract Student queryStudentByNo (int stuNo); //按照“约定”编写的“查询全部学生”的接口方法 public abstract List<Student> queryAllStudents (); //按照“约定”编写的“增加一个学生”的接口方法 public abstract void addStudent(Student student); //按照“约定”编写的“根据学号,删除一个学生”的接口方法 public abstract void deleteStudentByNo(int stuNo); //按照“约定”编写的“根据学号,修改一个学生”的接口方法 public abstract void updateStudentByNo(int stuNo); }
(3) 修改的SQL映射文件studentMapper.xml:将mapper的namespace值修改为接口IStudentMapper.java的“包名+接口名”,如下,
<mapper namespace="org.lzy.mapper.IStudentMapper"> … </mapper>
MyBatis通过namespace的值来定位接口的路径,并在接口编写方法的月的约定来将SQL映射文件中的各个数据库标签(如、等)与接口中的方法一一对应的。有了接口方法和数据库标签的一一对应关系,也就可以直接通过接口中方法名来定位数据库标签,而不用再使用statement变量来定位数据库标签。
(4) 习惯上,我们在使用此种基于约定的“Mapper动态代理方式”实现MyBatis时,会把SQL映射文件和接口放在同一个包下。因此需要将项目中studentMapper.xml移动到接口所在包 “org.lzy.mapper”中。移动完后,注意要修改MyBatis配置文件(conf.xml)中的SQL配置文件路径,如下,
conf.xml
<configuration> … <mappers> <mapper resource="org/lzy/mapper/studentMapper.xml" /> </mappers> </configuration>
(5)在测试类中编写测试代码
采用Mapper动态代理方式,还需要借助于SqlSession接口中getMapper()方法,
方法 | 简介 |
---|---|
T getMapper(Class type) | 传入一个接口类型(接口.class)的对象,返回该接口的mapper代理对象。可以通过此mapper代理对象,来调用传入的那个接口对象中的所有方法。 |
public class TestMyBatis { … // 根据学号查询一个学生 public static void testQueryByNoWothMapper() throws IOException { String resource = "conf.xml"; Reader reader = Resources.getResourceAsReader(resource); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader); SqlSession session = sessionFactory.openSession(); // 传入IStudentMapper接口,返回该接口的mapper代理对象studentMapper IStudentMapper studentMapper = session.getMapper(IStudentMapper.class); //通过mapper代理对象studentMapper,来调用IStudentMapper接口中的方法 Student student = studentMapper.getStudentByNo(31); System.out.println(student); session.close(); } public static void main(String[] args) throws IOException { testQueryByNoWothMapper(); … } }
使用mapper代理的方法来开发MyBatis,开发者只需要按照一定的“约定”编写接口及接口中的方法,并且不用写接口的实现类,然后就可以直接通过接口中的方法来执行SQL映射文件中的SQL语句。在MyBatis官方文档中,也是推荐使用此种方式来开发程序。
相关文章推荐
- MyBatis集成spring相关配置
- Spring+Mybatis 整合例子
- mybatis 学习一
- Springboot+mybatis 搭配mybatis逆向工程
- Mybatis源码研究3:包和类的概述
- log4j之mybatis配置
- mybatis返回list
- 使用Mybatis-Generator的三种常用方式
- mybatis 多参数 list和String
- springmvc+mybatis+pgsql+jetbrick整合
- mybatis3 配置SQL输出到日志
- MyBatis从入门到放弃六:延迟加载、一级缓存、二级缓存
- mybatis中#和$符号的区别(转)
- MyBatis 动态SQL
- mybatis-spring集成:配置多数据库源中遇到的问题--MapperScannerConfigurer配置
- 深入了解MyBatis二级缓存
- Hibernate相对于Mybatis的缺陷
- Mybatis框架使用步骤
- mybatis学习
- Mybatis数据源与连接池