目录
MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。MyBatis摒除了大部分的JDBC代码、手工设置参数和结果集重获。MyBatis使用简单的XML和注解来配置和映射基本数据类型、Map接口和POJO到数据库记录
SqlSessionFactory是MyBatis框架的核心引擎
SqlSessionFacrtory包含了MyBatis最基础的元数据配置并且提供访问数据库的具体SqlSession实例的维护,通常使用SqlSessionFactoryBuilder创造一个SqlSessionFactory实例
配置MyBatis
基本配置
配置xml文件
configuration.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>
<!--加载数据库映射属性文件-->
<properties resource="com/conf/dbconf.properties"/>
<!--配置数据源信息-->
<environments default="bizdb">
<environment id="bizdb">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="url" value="${jdbc_url}"/>
<property name="username" value="${jdbc_user}"/>
<property name="driver" value="${jdbc_driver}"/>
<property name="password" value="${jdbc_password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/domin/department-mapper.xml"/>
</mappers>
</configuration>
当然,这里使用maven来找包
<!-- mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<!-- jdbc的包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
还有很多包,就不一一列举出来了
涉及到的jdbc的conf:
jdbc_url = jdbc:oracle:thin:@127.0.0.1:1521:system
jdbc_driver = oracle.jdbc.driver.OracleDriver
jdbc_user = system
jdbc_password = ****
构建 SqlSessionFactory,获取 SqlSession
package com.util.db;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
public class MySqlSessionManager {
/*配置myBatis基本元数据的外部xml文件路径*/
private static final String CONFIG_FILE = "com/conf/configuration.xml";
/*建立sqlsession*/
public static SqlSession getSqlSession(){
SqlSessionFactory ssf = newSqlSessionFactory();
SqlSession sqlSession = null;
sqlSession = ssf.openSession();
System.out.println("sqlSession实例" + sqlSession);
return sqlSession;
}
/*利用Resoure组件基于文件获取一个输入流*/
private static SqlSessionFactory newSqlSessionFactory(){
SqlSessionFactory ssf = null;
Reader reader = null;
try {
reader = Resources.getResourceAsReader(CONFIG_FILE);
ssf = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
return ssf;
}
}
创建类
Department.java
package com.domin;
import java.util.Date;
public class Department {
private String id;
private String name;
private String code;
private Date newDate;
private String descs;
public Department() {
}
public Department(String id, String name, String code, Date newDate, String descs) {
this.id = id;
this.name = name;
this.code = code;
this.newDate = newDate;
this.descs = descs;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Date getNewDate() {
return newDate;
}
public void setNewDate(Date newDate) {
this.newDate = newDate;
}
public String getDisc() {
return descs;
}
public void setDisc(String disc) {
this.descs = disc;
}
}
创建类相关映射文件配置xml
department-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="depns">
<select id="queryDeplist" resultType="com.domin.Department">
select "id","name","code","newdate","descs" from "department"
</select>
</mapper>
同时在configuration.xml中添加mapper
<mappers>
<mapper resource="com/domin/department-mapper.xml"/>
</mappers>
ok一切就绪,建立一个servlet来康康
package com.servlet;
import com.domin.Department;
import com.service.DepartmentService;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
public class testServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Department> list = DepartmentService.queryDeplist();
for(Department dep:list){
System.out.println("名字:" + dep.getName());
System.out.println("code:" + dep.getCode());
}
}
}
我在数据库中存入了一条数据
现在运行tomcat,这条数据打到了控制台上
采用注解的方式映射sql
注解在接口当中
IDepartmentMapper,java
package com.dao;
import com.domin.Department;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface IDepartmentMapper {
@Select("select * from \"department\"")
public List<Department> queryDepList();
}
在configuration.xml中,添加mapper
<mappers>
<!-- <mapper resource="com/domin/department-mapper.xml"/>-->
<mapper class="com.dao.IDepartmentMapper"/>
</mappers>
在DepartmentDao.java建立方法(还有DepartmenetService调用,就不演示了)
/*利用注解的方式实现sql映射执行*/
public static List<Department> queryDeplist2ByMapper(){
SqlSession sqlSession = MySqlSessionManager.getSqlSession();
return sqlSession.getMapper(IDepartmentMapper.class).queryDepList();
}
在sevlet中调用:
List<Department> list2 = DepartmentService.queryDeplistByMapper();
for(Department dep:list2){
System.out.println("名字:" + dep.getName());
System.out.println("code:" + dep.getCode());
}
启动tomcat,同样将结果打出来了
主要API生命周期
SqlSessionFactoryBuilder实例的主要作用是为了创建一个SqlSessionFactory而生存,因此在创建一个SqlSessionFactory实例成功,这个实例就可以别丢弃,所有长时间保存此对象在内存没多大意义,推荐在某个方法体内使用
SqlSessionFactory创建后在整个应用过程中始终存储在,一个应用中一般不涉及多个数据源时,也只会有一个SqlSessionFactory实例,所以它的生命周期应该是Application。通常定义此实例为单例模式
SqlSession是操作数据库业务最主要的接口,此实例不是线程安全的不能共享此对象。它的作用域应在当前请求中或一个方法体内,也不应使用类的静态变量来引用一个Sqlession实例,甚至不要使用类的一个实例变量来引用。
绝对不能在web应用中的某个会话作用域中引用此对象,应随着用户的某个HTTP请求结束而释放此对象,在使用完SqlSession执行完数据库操作后要及时关闭SqlSession
Mapper实例必需由一个SqlSession对象所创建,而且在使用Mapper实例实现数据库操作时也必需保证创建它的SqlSession是处于打开的状态下
因此Mapperr的生命周期通常和SqlSession的生命周期相同,在一个SqlSesison关闭或销毁后,基于此SqlSesison创建的Mapper实例将不能被使用
别名typeAliases
在configuration.xml(Mybatis配置文件xml)中,由typeAliases、typeAliase配置类的别名:
<typeAliases>
<typeAlias type="com.domin.Department" alias="dept"/>
</typeAliases>
在department-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="depns">
<select id="queryDeplist" resultType="dept">
select "id","name","code","newdate","descs" from "department"
</select>
</mapper>
这里resultType的值为dept,使用了别名
Mybatis预定义类型别名:
所用基本数据烈性别名是加前缀下划线(如int类型别名为_int)
所有基础类型的包装类行为首字母变小写(如Integer类型别名为integer)
<select id="queryCountNum" resultType="integer">
select count(id) from department
</select>
…dao.java
/*计算部门数*/
public static List<Integer> queryCountNum(){
SqlSession sqlSession = MySqlSessionManager.getSqlSession();
return sqlSession.selectList("depns.queryCountNum");
}
sevlet
System.out.println("共有部门数:" + DepartmentDao.queryCountNum().get(0));
结果略
environments配置
environments用来配置数据源信息,其至少要有一个数据源(environmnent子元素)配置
transactionManager子元素定义myBatis处理数据库事务的类型
myBatis处理数据库事务处理支持两种类型:
JDBC:此类型使用的提交和回滚功能,它联考使用连接的数据源来管理事务的作用域
MANAGED:此类型什么不做,从不提交、回滚和关闭连接。让其他容器或代码实现中来管理事务的全部生命周期(如spring或者JAVAEE容器)
dataSoure子元素
用来配置在某个环境下JDBC数据库属性信息。MyBatis提供三种类型的数据源
UNPOOLED:此类型每次请求的时候简单打开和关闭一个连接,不使用任何连接池技术,性能较差不推荐
POOLED:此类型缓存JDBC连接对象用于避免每次都要连接和生成连接实例而需要的验证时间(使用连接池的优点)。对于并发WEB应用,建议使用此种方式的数据源
JNDI:此类型使用匹配应用服务器上配置的数据源,通过java命名目录接口方式查找一个服务器上的数据源对象
mappers
mappers元素的总告诉Mybatis框架在初始化时如何加载SQLMap映射文件或标识了注解的接口,上面有写过,这里略了
SQL映射
select(带参数)
之前也演示过了,这里演示带有参数的
sql语句可以用:<![CDATA[]]>包围sql语句告知系统将语句汇总任何特殊字符按非语义处理.
select的属性:
下面以查询一个customer来说明:
customer.java
package com.domin;
public class Customer {
private String name;
private int age;
private String sex;
//以下省略了构造器和get、set方法
customer-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="cus">
<select id="queryCustomer" parameterType="int" resultType="com.domin.Customer">
<![CDATA[select "name","age","sex" from "customer" where "age" > #{age}]]>
</select>
</mapper>
注意,这个mapper的namespace要写上,不然会报错
还有,<select>中的<![CDATA[]]>在csdn这里竟然显示灰色,实际上不是注释啊!
#{}表示一个变量,里面的age没啥含义,用来占位
customDao.java,写上查询方法
package com.dao;
import com.domin.Customer;
import com.util.db.MySqlSessionManager;
import org.apache.ibatis.session.SqlSession;
import java.util.List;
public class CustomerDao {
public static List<Customer> queryCustomer(int age){
List<Customer> list = null;
SqlSession sqlSession = MySqlSessionManager.getSqlSession();
list = sqlSession.selectList("cus.queryCustomer",age);
return list;
}
}
这里传入了age这个参数
在servlet
List<Customer> list3 = CustomerDao.queryCustomer(18);
for(Customer c:list3){
System.out.println(c.getName() + " " + c.getAge() + " " + c.getSex());
}
哦,还有,在configuration.xml中加上<mapper>
<mapper resource="com/domin/customer-mapper.xml"/>
我的数据库中的customer:
结果:
selectOne及返回集合
selectOne:只返回一个,而不是像selectList那样返回一个list
(接上)
customer.xml
<select id="queryCustomerByName" parameterType="String" resultType="map">
<![CDATA[select name,age,sex from customer where name = #{
name}]]>
</select>
dao.java
public static Map<String,Object> queryCustomerByName(String name){
return MySqlSessionManager.getSqlSession().selectOne("cus.queryCustomerByName",name);
}
servlet
Map<String,Object> map = CustomerDao.queryCustomerByName("liang");
System.out.println(map.get("NAME").toString());
System.out.println(map.get("AGE").toString());
System.out.println(map.get("SEX").toString());
注意,这里的key要大写,否则报错
结果:
insert和update
<insert><update>通用属性
id*:SQL体育局引用唯一标识,必需属性
flushCache:执行过呢更新时是否刷新缓存数据(true、false)
useGeneratedKeys:使用利用自生成唯一标识(主键),使用域自动增长主键表
keyProperty:指定在保存对象时自动生成标识反馈到对象的哪个属性
keyColumn:指定在保存对象时自动生成标识映射道底层表的主键列名
databaseId:指定对那种数据源进行数据操作,与全局配置<databaseIdProvide>对应,用来切换数据库
insert使用演示
在department-mapper.xml中添加insert方法,传入一个map
<insert id="addCustomer" parameterType="map" keyColumn="ID" keyProperty="id"
flushCache="true" statementType="PREPARED">
<![CDATA[insert into department(id,name,code,newdate,descs)
values(#{id},#{name},#{code},#{newdate},#{descs})]]>
</insert>
在DepartmentDao.java中:
public static int addCustomer(Map<String,Object> map){
SqlSession sqlSession = MySqlSessionManager.getSqlSession();
int r = sqlSession.insert("depns.addCustomer",map);
sqlSession.commit();
sqlSession.close();
return r;
}
注意,要加上commit方法,不然找不到insert的信息
在servlet中添加map,并作为参数传入到addCustomer中
Map<String,Object> map = new HashMap<String,Object>();
map.put("id","1");
map.put("name","陈正");
map.put("code","111");
map.put("newdate",new Date());
map.put("descs","备注");
int r = DepartmentDao.addCustomer(map);
System.out.println("插入:" + r);
结果为1,说明成功:
去软件看看,发现也成功了
update使用演示
department-mapper.xml
<update id="updateDepartment" parameterType="map" keyColumn="ID" keyProperty="id"
statementType="PREPARED">
update department set name=#{name} where id = #{id}
</update>
Dao.java
public static int updateDepartment(Map<String,Object> map){
SqlSession sqlSession = MySqlSessionManager.getSqlSession();
int result = sqlSession.update("depns.updateDepartment",map);
sqlSession.commit();
sqlSession.close();
return result;
}
servlet
Map<String,Object> map = new HashMap<String, Object>();
map.put("id","33");
map.put("name","钓鱼部");
DepartmentDao.updateDepartment(map);
结果(与insert演示的对比,摸鱼部改成钓鱼部):
delete
直接演示;
department-mapper.xml
<delete id="deleteDepartmentById" flushCache="true"
statementType="PREPARED" parameterType="string">
delete from department where id = #{id}
</delete>
…Dao.java
public static int deleteDepartmentById(String id){
SqlSession sqlSession = MySqlSessionManager.getSqlSession();
int result = sqlSession.delete("depns.deleteDepartmentById",id);
sqlSession.commit();
sqlSession.close();
return result;
}
servlet
删除id为1的所有行
DepartmentDao.deleteDepartmentById("1");
结果:
sql重用
直接上例子:
sql标签,取代这些字符串
<sql id="depCommon">id,name,code,newdate,descs</sql>
这个标签放入<mapper>即可
然后修改查询的<select>
<select id="queryDeplist" resultType="dept" fetchSize="2">
select <include refid="depCommon"/> from department
</select>
效果相同,就不贴servlet代码了
这里的select语句不能包裹在CDATA里,不然<include>就没作用了,还会报错,解决方式未知,直接就不用CDATA了。
myBaits缓存
建立缓存:
数据缓存可以增加数据的访问操作效率,myBatis提供了设置sql的缓存策略和操sql映射中引用缓存策略;
myBatis使用cache元素在sql映射中设置缓存策略及使用ref-cache引用缓存策略。
MyBatis中的缓存策略
LRU-最近最少使用法(默认):移除最近较长周期内都没用被使用的对象
FIFO-先进先出:移出队列里较早的对象
SOFT-软引用:基于软引用规则,使用垃圾回收机制来移出对象
WEAK-弱引用:基于弱引用规则,使用垃圾回收机制来强制性地移出对象
cache-ref元素实现从一个mapper中引用到当前的mapper中的缓存策略并应用
myBatis缓存机制
二级缓存的使用配置
globalCatche.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="global-catche">
<!--配置myBatis全局二级缓存-->
<cache eviction="LRU" readOnly="true" flushInterval="60000" size="500"/>
</mapper>
configuration.xml中mappers中写入来源
<mappers>
<mapper resource="com/domin/department-mapper.xml"/>
<mapper class="com.dao.IDepartmentMapper"/>
<mapper resource="com/domin/customer-mapper.xml"/>
<mapper resource="com/conf/globalCatche.xml"/>
</mappers>
在department-mapper.xml中调用
<cache-ref namespace="global-catche"/>
二级缓存的缺陷
针对一个表的操作不再它独立的namespace下执行(单表操作)
多表操作严重受限制,导致获取缓存数据发生不正确
缓存对象类型必须是序列化的实现
数据量比较庞大时可能出现更多的未知错误