您的位置:首页 > 其它

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.jarMyBatis的类库
mybatis-3.x.x-javadoc.jarMybatis的API帮助文档
mybatis-3.x.x-sources.jarMybatis的源代码
mybatis-3.x.x.pdfMyBatis的开发向导
② 创建一个普通的Java项目(项目名MyBatisDemo),并在该项目的src目录下,创建一个libs目录(new → Folder)并存放mybatis-3.x.x.jar和ojdbc6.jar(oracle驱动包),再将这两个jar包设置为构建目录(Build Path),如图,



③ 创建(或使用之前已有的)“学生表”,各字段及类型如下:

字段名类型字段名类型
stuNonumberstuAgenumber
stuNamenvarchar2(50)garNamenvarchar2(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())等
MANAGEDMyBatis自身不会去管理事务,而是把事务交给容器托管(比如Spring、JBOSS、Weblogic容器)。默认情况会关闭连接,若不想关闭则需要如下配置:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
(4)数据源

<dataSource type="POOLED">


type: 指定数据源类型

MyBatis中有三种数据源类型,UNPOOLED、 POOLED和JNDI:

① UNPOOLED :每次被请求时简单打开和关闭连接,需要配置的以下属性:

属性名简介
driverJDBC驱动的Java全类名
url数据库的JDBC URL地址
username登陆数据库的用户名
password登陆数据库的密码
defaultTransactionIsolationLevel默认的连接事务隔离级别
② POOLED:简单的数据库连接池类型,它使得数据库连接可被复用,不必在每次请求时都去创建一个物理的连接。

③ 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 持久层框架