文章目录
Mybatis:
-
学习Mybatis的几个步骤
- 入门
- 配置文件
- 映射文件
- 映射接口
- Session对象
- 单表映射
- 多表映射
- 动态sql
- 特殊功能(缓存,分页)
- 注解配置
-
Mybatis需要手动提交,jdbc是自动提交
-
xml中写sql语句不需要分号,否则会报错
当前有很多Java实现的持久化框架,而MyBatis流行起来有以下原因:
- 它消除了大量的JDBC冗余代码:Java通过JDBC的API来操作关系型数据库,但是JDBC是一个非常底层的API,我们需要书写大量的代码来完成对数据库的操作。例如一个插入操作(参考之前学习JDBC时候的代码实例)但是使用mybatis来完成相同的插入操作要简单方便灵活的多:
第一步:在SQLMapper映射配置文件中配置SQL语句,假定为StudentMapper.xml
<insert id="insertStudent" parameterType="Student">
INSERT INTO STUDENTS(ID,NAME,EMAIL)
VALUES(#{id},#{name},#{email})
</insert>
第二步:创建一个StudentMapper接口
public interface StudentMapper{
void insertStudent(Student student);
}
第三步:编写java代码完成插入操作:(动态代理)
SqlSession session = getSqlSessionFactory().openSession();
//通过动态代理自动生成接口的实现类 因此这里的mapper就是StudentMapper接口的实现类
StudentMapper mapper = session.getMapper(StudentMapper.class);
mapper.insertStudent(student);
配置文件和映射文件
配置文件:
MyBatis-config.xml 其中包括数据库的连接信息,类型名称,映射文件路径(根据所有填上去的映射文件,建立ORM映射)等
//固定抬头,dtd约束等
<?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>
//别名
<typeAliases>
<typeAlias alias="Student" type="com.briup.pojo.Student" />
</typeAliases>
<!-- 数据库连接信息 -->
<environments default="development">
<environment id="development">
<transaction Manager type="JDBC" />
<dataSource type="POOLED">
<!--
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
-->
<property name="driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:XE" />
<property name="username" value="briup" />
<property name="password" value="briup" />
</dataSource>
</environment>
</environments>
<!-- 映射文件路径 -->
<mappers>
<mapper resource="com/briup/pojo/StudentMapper.xml" />
...
</mappers>
</configuration>
environments
environments是配置mybatis当前工作的数据库环境的地方
MyBatis支持配置多个dataSource环境,可以将应用部署到不同的环境上,可以通过配置 配置不指定数据库时,sqlSession操作的数据库
如果你的应用需要连接多个数据库,你需要将每个数据库配置成独立的环境,并且为每一个数据库创建一个SqlSessionFactory
例如:
<environments default="shoppingcart">
数据库shoppingcart
<environment id="shoppingcart">
<transactionManager type="MANAGED" />
<dataSource type="JNDI">
<property name="data_source" value="java:comp/jdbc/ShoppingcartDS" />
</dataSource>
</environment>
数据库reports
<environment id="reports">
<transaction Managertype="MANAGED" />
<dataSource type="JNDI">
<property name="data_source" value="java:comp/jdbc/ReportsDS" />
</dataSource>
</environment>
</environments>
//我们可以为以上每个环境创建一个SqlSessionFactory
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//默认的环境
defaultSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//统计明细的环境
cartSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "shoppingcart");
//统计报表的环境
reportSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "reports");
//注意:对于environments,我们可以在其中配置多个environment子元素,
//同时还需要在environment中配置dataSource和transactionManager元素。
dataSource
dataSource表示的是数据源:至少会包括该连接数据库的各种信息
<dataSource type="POOLED">
<property name="driver" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:XE" />
<property name="username" value="briup" />
<property name="password" value="briup" />
</dataSource>
dataSource的类型type属性可以配置成其内置类型之一,如UNPOOLED,POOLED,JNDI
- UNPOOLED,MyBatis会为每一个数据库操作创建一个新的连接,使用完了并关闭它,该方式适用于只有小规模数量并发用户的简单应用程序上。
- POOLED,MyBatis会创建一个数据库连接池,连接池中的一个连接将会被用作数据库操作。一旦数据库操作完成,MyBatis会将此连接返回给连接池。在开发或测试环境中,经常使用此种方式。
- JNDI(Java Naming and Directory Interface , Java命名和目录接口, 是SUN公司提供的一种标准的Java命名系统接口),MyBatis从在应用服务器向配置好的JNDI数据源dataSource获取数据库连接。在生产环境中,优先考虑这种方式。
transactionManager
MyBatis支持两种类型的事务管理器:
- JDBC 和 MANAGED. JDBC事务管理器的使用,是在【jdbc程序】负责管理数据库连接的生命周期(提交、回退等等)的时候。如果将TransactionManager 属性设置成JDBC,MyBatis内部将使用JdbcTransactionFactory类创建TransactionManager。例如,部署到ApacheTomcat的应用程序,需要应用程序自己管理事务。
- MANAGED 事务管理器的使用,是在【应用服务器】负责管理数据库连接生命周期的时候。如果将TransactionManager属性设置成MANAGED时,MyBatis内部使用ManagedTransactionFactory 类创建事务管理器TransactionManager。例如,当一个Java EE的应用程序部署在类似JBoss,WebLogic,GlassFish应用服务器上时,它们会使用EJB进行应用服务器的事务管理能力。在这些管理环境中,你可以使用MANAGED事务管理器。
注:Managed 是托管的意思,即我们编写的应用程序本身不去管理事务,而是把事务管理交给应用所在的服务器进行管理。
properties
属性配置元素properties可以将配置值写死到mybatis-config.xml中,也可以具体到一个属性文件中,并且使用属性文件的key名作为占位符.
在上述的配置中,我们将数据库连接属性配置到了application.properties文件中,并且为driver,URL等属性使用了占位符.
在applications.properties文件中配置数据库连接参数,如下所示:
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:XE
jdbc.username=test
jdbc.password=test
在mybatis-config.xml文件中,为属性使用application.properties文件中定义的占位符:
<!--application.properties文件-->
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:XE
<!--
读取application.properties文件中的数据key-value的形式
注意:是applications.properties文件中的值优先级高;即:如果出现一个名字相同的变量,值会是文件中的
注意:DTD约束规定,如果出现properties标签,必须出现在最上面
-->
<properties resource="application.properties">
<property name="jdbc.username" value="briup" />
<property name="jdbc.password" value="briup" />
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
typeAliases
在SQLMapper配置文件中,对于resultType和parameterType属性值,我们需要使用JavaBean 的完全限定名。
<select id="findStudentById" parameterType="int" resultType="com.briup.pojo.Student">
SELECT STUD_ID AS ID, NAME, EMAIL, DOB
FROM STUDENTS WHERE STUD_ID=#{Id}
</select>
<update id="updateStudent" parameterType="com.briup.pojo.Student">
UPDATE STUDENTS
SET NAME=#{name}, EMAIL=#{email}, DOB=#{dob}
WHERE STUD_ID=#{id}
</update>
<!--
注:
parameterType表示将来调用这个sql语句的时候所传的参数的类型(参数值或者参数对象里面的属性值,用来替换sql语句中的占位符)
resultType表示将来调用这个sql语句的时候所返回的结果的类型(方便mybatis给我们自动封装结果集)
-->
方法1:
这里我们为resultType和parameterType属性值设置为Student类型的完全限定名:com.briup.com.Student
我们可以为完全限定名取一个别名(在mybatis-config.xml配置文件中)然后就可以在需要使用完全限定名的地方使用别名,而不是到处使用完全限定名。如下例子所示,为完全限定名起一个别名:
<typeAliases>
<typeAlias alias="Student" type="com.briup.pojo.Student" />
</typeAliases>
然后在SQLMapper映射文件中, 如下使用Student的别名:
<select id="findStudentById" parameterType="int" resultType="Student">
SELECT STUD_ID AS ID, NAME, EMAIL, DOB
FROM STUDENTS WHERE STUD_ID=#{id}
</select>
<update id="updateStudent" parameterType="Student">
UPDATE STUDENTS
SET NAME=#{name}, EMAIL=#{email}, DOB=#{dob}
WHERE STUD_ID=#{id}
</update>
方法2:
你可以不用为每一个JavaBean单独定义别名,你可以为配置出需要取别名的类的所在的包(package),MyBatis会自动扫描包内定义的类,然后分别为每个类注册一个小写字母开头的简单类名形式的别名。如下所示:
<typeAliases>
<package name="com.briup.pojo" />
</typeAliases>
如果Student.java和 Teacher.java 定义在com.briup.pojo包中,则 com.briup.pojo.Student的别名会被注册为student。而com.briup.pojo.Teacher别名将会被注册为teacher
还有另外一种方式为JavaBeans起别名,使用注解 @Alias:
@Alias("stu")
public class Student{
....
}
注意:@Alias注解将会覆盖配置文件中的定义,并且需要配合给包起别名一起使用
typeHandlers
当MyBatis将一个Java对象作为输入参数执行INSERT语句操作时,它会创建一个PreparedStatement对象,并且使用setXXX()方法对占位符设置相应的参数值 。这里,XXX可以是Int,String,Date 等 Java对象属性类型的任意一个。示例如下:
INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB)
VALUES(#{stud Id},#{name},#{email},#{dob})
为执行这个语句,MyBatis将采取以下一系列动作:
创建一个有占位符的PreparedStatement接口,如下:
Prepared Statement ps = connection.prepare Statement
(“INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(?,?,?,?)”);
检查Student对象的属性studId的类型,然后使用合适setXXX方法去设置参数值。这里studId是integer类型,所以会使用setInt()方法:ps.setInt(1,student.getStudId());
类似地,对于name和email属性都是String类型MyBatis使用setString()方法设置参数。
至于dob属性, MyBatis会使用setDate()方法设置dob处占位符位置的值。
MyBaits会将java.util.Date类型转换为java.sql.Timestamp并设值:
ps.setTimestamp(4, new Timestamp((student.getDob()).getTime()));
但MyBatis是怎么知道对于Integer类型属性使用setInt()和String类型属性使用setString()方法呢?其实MyBatis是通过使用类型处理器typeHandlers来决定这么做的。
MyBatis对于以下的类型使用内建的类型处理器:所有的基本数据类型、基本类型的包裹类型、 byte[]、java.util.Date、java.sql.Date、java,sql.Time、java.sql.Timestamp、java枚举类型等。所以当MyBatis发现属性的类型属于上述类型,他会使用对应的类型处理器将值设置到PreparedStatement中,同样地,当SQL结果集封装成java类对象的时候,也有类似的过程。
那如果有一个自定义的类型,怎么存储存储到数据库呢?示例如下:假设表STUDENTS 有一个 PHONE 字段,类型为 VARCHAR2(15),而 Student类有一个自定义类型属性
alter table students add phone varchar2(15);
alter table students drop column phone;
映射文件
占位符(#{name}这样的)其中的大小写是否有区别要看这样的引用变量是否涉及到对象,因SQL是大小写不敏感的,而Mybatis是大小写敏感的,如果需要从对象中调用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.briup.pojo.StudentMapper">
<resultMap type="Student" id="StudentResult">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="email" column="email" />
</resultMap>
<select id="findAllStudents" resultMap="StudentResult">
SELECT * FROM STUDENTS
</select>
<select id="findStudentById" parameterType="int" re sultType="Student">
SELECT ID AS STUDID, NAME, EMAIL
FROM STUDENTS WHERE ID=#{Id}
</select>
<insert id="insertStudent" parameterType="Student">
INSERT INTO STUDENTS(ID,NAME,EMAIL)
VALUES(#{id },#{name},#{email})
</insert>
</mapper>
查询操作:
-
查询出的结果Mybatis会自动封装成结果集(用集合的方式存储对象)因此需要数据库列名和对象属性名的对应关系;Mybatis会通过列名前面加set的方法找到对应关系,并调用方法,使其创建为对象并存储在其中
-
因此就需要数据库列名和对象的属性名相同,如果不同的话,就需要处理
- 方法一:在sql语句中使用as给列起别名,这样就又能找到了
- 方法二:使用resultMap(同样适用于select*)创建映射关系
<!-- 结果集映射: ?:id和result的区别 --> <resultMap type="Student" id="StudentResult"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="email" column="email" /> </resultMap> <select id="findAllStudents" resultMap="StudentResult"> SELECT * FROM STUDENTS </select>
Java部分
映射接口
除了Jar包和配置文件之外,还必须要有调用SQl语句执行的接口(XXXMapper.java接口中的方法名要和配置文件中的SQL映射名称相同)
实际上要想实现操纵SQL的功能,使用的还是Java代码,接口给框架一个实现方法的机会,配置文件表明了我们想要的功能,框架通过动态代理机制自动帮我们生成该接口的实现类对象
public interface StudentMapper{
//三个抽象方法对应xml文件中的三个语句块
List<Student> findAllStudents();
Student findStudentById(Interger Id);
void insertStudent(Student student);
}
SqlSession接口和sqlSessionFactory接口
调用方法始终还是要通过对象来调用,这是Java作为面向对象编程语言的基本原则 同时想要调用抽象方法,就需要创建它的实现类对 象,
因此我们需要获得XxxxMapper.java接口的实现类对象,才能使用其中的方法(同时也是对应的XML文件中的SQL语句块)我们需要使用sqlSession产生这个实现类
/*
1. 通过输入流的方式读取mybatis-config.xml配置文件
2. 通过这个流建一个sqlSessionFactory工厂,并创建一个工厂对象
3. 工厂对象有一个方法(产品线).OpenSession() 可以获得一个sqlSession对象
*/
InputStream inputStream = Resources.getResourcesAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//产生StudentMapper接口的实现类对象mapper
StudentMapper mapper = session.getMapper(StudentMapper.class);
//调用方法
mapper.insertStudent(new Studetn(1,"tom","tom@gmail.com"));