这里我使用mybatis-3.1.1版本做分析,更新的版本自己去github下吧,好了这是下载到的项目:
2.在src目录下创建mybatis配置文件Configuration.xml,代码如下:
3.准备一下测试数据吧:
/*
Navicat MySQL Data Transfer
Source Server : raykipp
Source Server Version : 50627
Source Host : 127.0.0.1:3306
Source Database : test
Target Server Type : MYSQL
Target Server Version : 50627
File Encoding : 65001
Date: 2016-05-15 11:21:37
*/SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for `t_admin_permission_group`-- ----------------------------DROPTABLEIFEXISTS`t_admin_permission_group`;CREATETABLE`t_admin_permission_group` (
`groupId`bigint(20) NOTNULL AUTO_INCREMENT COMMENT'权限组表Id',
`groupName`varchar(20) DEFAULTNULLCOMMENT'权限名称',
`status`int(10) DEFAULTNULLCOMMENT'状态,1表示有效,0表示无效',
`orderId`int(10) DEFAULT'0'COMMENT'排序号',
`creater`varchar(20) DEFAULTNULLCOMMENT'创建者',
`createTime` datetime DEFAULTNULLCOMMENT'创建时间',
`modifyer`varchar(20) DEFAULTNULLCOMMENT'修改者',
`modifyTime` datetime DEFAULTNULLCOMMENT'修改时间',
PRIMARY KEY (`groupId`)
) ENGINE=InnoDB AUTO_INCREMENT=13DEFAULTCHARSET=utf8;-- ------------------------------ Records of t_admin_permission_group-- ----------------------------INSERTINTO`t_admin_permission_group`VALUES ('1', '用户管理', '1', '1', 'wxh', '2015-06-21 09:41:35', 'wxh', '2015-06-21 09:41:43');
package com.raykip.study.mybatis.model;
import java.sql.Timestamp;
publicclassAdminPermissionGroup {
/**权限组表Id*/private Long groupId;
/**权限组名称*/private String groupName;
/**状态,1表示有效,0表示无效*/privateint status;
/**排序号*/privateint orderId;
/**创建者*/private String creater;
/**创建时间*/private Timestamp createTime;
/**修改者*/private String modifyer;
/**修改时间*/private Timestamp modifyTime;
public Long getGroupId() {
return groupId;
}
publicvoidsetGroupId(Long groupId) {
this.groupId = groupId;
}
public String getGroupName() {
return groupName;
}
publicvoidsetGroupName(String groupName) {
this.groupName = groupName;
}
publicintgetStatus() {
return status;
}
publicvoidsetStatus(int status) {
this.status = status;
}
publicintgetOrderId() {
return orderId;
}
publicvoidsetOrderId(int orderId) {
this.orderId = orderId;
}
public String getCreater() {
return creater;
}
publicvoidsetCreater(String creater) {
this.creater = creater;
}
public Timestamp getCreateTime() {
return createTime;
}
publicvoidsetCreateTime(Timestamp createTime) {
this.createTime = createTime;
}
public String getModifyer() {
return modifyer;
}
publicvoidsetModifyer(String modifyer) {
this.modifyer = modifyer;
}
public Timestamp getModifyTime() {
return modifyTime;
}
publicvoidsetModifyTime(Timestamp modifyTime) {
this.modifyTime = modifyTime;
}
}
AdminPermissionGroup.xml
groupId,groupName,status,orderId,creater,createTime,modifyer,modifyTime
insert into t_admin_permission_group (
groupId,groupName,status,orderId,creater,createTime,modifyer,modifyTime
)
values (
#{groupId,jdbcType=BIGINT},
#{groupName,jdbcType=VARCHAR},
#{status,jdbcType=INTEGER},
#{orderId,jdbcType=INTEGER},
#{creater,jdbcType=VARCHAR},
#{createTime,jdbcType=TIMESTAMP},
#{modifyer,jdbcType=VARCHAR},
#{modifyTime,jdbcType=TIMESTAMP}
)
insert into t_admin_permission_group
groupId,
groupName,
status,
orderId,
creater,
createTime,
modifyer,
modifyTime,
#{groupId,jdbcType=BIGINT},
#{groupName,jdbcType=VARCHAR},
#{status,jdbcType=INTEGER},
#{orderId,jdbcType=INTEGER},
#{creater,jdbcType=VARCHAR},
#{createTime,jdbcType=TIMESTAMP},
#{modifyer,jdbcType=VARCHAR},
#{modifyTime,jdbcType=TIMESTAMP},
insert into t_admin_permission_group
(groupId,groupName,status,orderId,creater,createTime,modifyer,modifyTime) values
(
#{groupId,jdbcType=BIGINT},
#{groupName,jdbcType=VARCHAR},
#{status,jdbcType=INTEGER},
#{orderId,jdbcType=INTEGER},
#{creater,jdbcType=VARCHAR},
#{createTime,jdbcType=TIMESTAMP},
#{modifyer,jdbcType=VARCHAR},
#{modifyTime,jdbcType=TIMESTAMP}
)
delete from t_admin_permission_group
where groupId = #{groupId,jdbcType=BIGINT}
update t_admin_permission_group
groupName = #{groupName,jdbcType=VARCHAR},
status = #{status,jdbcType=INTEGER},
orderId = #{orderId,jdbcType=INTEGER},
creater = #{creater,jdbcType=VARCHAR},
createTime = #{createTime,jdbcType=TIMESTAMP},
modifyer = #{modifyer,jdbcType=VARCHAR},
modifyTime = #{modifyTime,jdbcType=TIMESTAMP}
where groupId = #{groupId,jdbcType=BIGINT}
update t_admin_permission_group set
groupName = #{groupName,jdbcType=VARCHAR},
status = #{status,jdbcType=INTEGER},
orderId = #{orderId,jdbcType=INTEGER},
creater = #{creater,jdbcType=VARCHAR},
createTime = #{createTime,jdbcType=TIMESTAMP},
modifyer = #{modifyer,jdbcType=VARCHAR},
modifyTime = #{modifyTime,jdbcType=TIMESTAMP}
where groupId = #{groupId,jdbcType=BIGINT}
update t_admin_permission_group
groupId = #{groupId,jdbcType=BIGINT},
groupName = #{groupName,jdbcType=VARCHAR},
status = #{status,jdbcType=INTEGER},
orderId = #{orderId,jdbcType=INTEGER},
creater = #{creater,jdbcType=VARCHAR},
createTime = #{createTime,jdbcType=TIMESTAMP},
modifyer = #{modifyer,jdbcType=VARCHAR},
modifyTime = #{modifyTime,jdbcType=TIMESTAMP}
where groupId in
#{item.groupId}
5.写一个测试类测试一下吧!
package com.raykip.study.mybatis.test;
import java.io.Reader;
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 com.alibaba.fastjson.JSON;
import com.raykip.study.mybatis.model.AdminPermissionGroup;
public class SqlsessionTest{
privatestaticSqlSessionFactory sqlSessionFactory;
privatestaticReader reader;
static{
try{
reader = Resources.getResourceAsReader("Configuration.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}catch(Exception e){
e.printStackTrace();
}
}
publicstaticSqlSessionFactory getSession(){
return sqlSessionFactory;
}
publicstatic void main(String[] args) {
SqlSession session = sqlSessionFactory.openSession();
try {
AdminPermissionGroup group = (AdminPermissionGroup) session.selectOne("AdminPermissionGroup.selectByPrimaryKey", 1);
System.out.println(JSON.toJSONString(group));
} finally {
session.close();
}
}
}
6.运行结果如下:
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
{"createTime":1434850895000,"creater":"wxh","groupId":1,"groupName":"用户管理","modifyTime":1434850903000,"modifyer":"wxh","orderId":1,"status":1}
/*
* Copyright 2009-2012 The MyBatis Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/package org.apache.ibatis.session;
import java.sql.Connection;
publicinterfaceSqlSessionFactory{
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
http://tool.oschina.net/apidocs/apidoc?api=mybatis-3.1.1这个文档有这2个类的说明,也就是说你可以使用这2个类来获取sqlSessionFactory,比如:
sqlSessionFactory = SqlSessionManager.newInstance(reader);
或者
DataSource dataSource = new PooledDataSource("com.mysql.jdbc.Driver",
"jdbc:mysql://127.0.0.1:3306/circcenter?useUnicode=true&characterEncoding=UTF-8", "root", "root");
Environment environment = new Environment("test", new JdbcTransactionFactory(), dataSource);
Configurationconfiguration = newConfiguration(environment);
configuration.addMapper(AdminPermissionGroup.class);
//SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
sqlSessionFactory = new DefaultSqlSessionFactory(configuration);
通过看代码,发现SqlSessionFactoryBuilder类起到关键作用,OK我们看一下这个类:
首先用Eclipse工具查看SqlSessionFactoryBuilder类的Outline视图:
其实这个三个方法才是最重要的:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) public SqlSessionFactory build(Reader reader, String environment, Properties properties) public SqlSessionFactory build(Configuration config)
通过上面这几行代码,就能看出基于XML文件的这种构造方式,通过从XML中读取信息的工作之后,也是构造出Configuration对象之后再继续进行SqlSessionFactory的构建工作的,只是多了些XML的解析工作,所以我们只需单刀直入,直按分析编程构造方式的代码就可以了,或者是直接分析 build(parser.parse())这句代码(参数产生过程先跳过)
编程构造方式的build方法源码如下(基于xml的构造方式的build(parser.parse())最终也是调了这个代码):
public SqlSessionFactory build(Configuration config) { returnnew DefaultSqlSessionFactory(config); }
其实这么看来SqlSessionFactory在mybatis的默认实现类为org.apache.ibatis.session.defaults.DefaultSqlSessionFactory , 其构造过程主要是注入了Configuration的实例对象,Configuration的实例对象即可通过解析xml配置文件产生,也可能通过代码直接构造。以上代码使用了一个设计模式:建设者模式(Builder),SqlSessionFactoryBuilder扮演具体的建造者,Configuration类则负责建造的细节工作,SqlSession则是建造出来的产品。
以下是类图和建造者模式的基本形态图,读者自行对照阅读。
构造者模式是一种对象的创建模式。它可以将一个复杂对象的内部构成特征与对象的构建过程完全分开。
package com.raykip.study.mybatis.util;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
publicclassSqlSessionFactoryUtil{ privatestatic SqlSessionFactory sqlSessionFactory;
publicstatic SqlSessionFactory getSqlSessionFactory()throws IOException{
if(sqlSessionFactory==null){
Reader reader = Resources.getResourceAsReader("Configuration.xml");
returnnew SqlSessionFactoryBuilder().build(reader);
}else{
return sqlSessionFactory;
}
}
}
好了,我们再来看下Sqlsession这个接口,我相信大家对这个类不会陌生,它是一个会话,与数据库的会话,通过它可以执行sql返回结果集、提交/回滚事务等操作。还是看一下outline图:
相信看到这些方法,可以猜到这些方法是干嘛的,包含的select、insert、update、delete方法都是基本的数据库操作,我们可以利用这些方法封装我们自己的BaseDao,并进行扩展。实现类有这2个:
public T selectOne(String statement, Object parameter){
// Popular vote was to return null on 0 results and throw exception on too many.
List list = this.selectList(statement, parameter);
if (list.size() == 1) {
returnlist.get(0);
} elseif (list.size() > 1) {
thrownew TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
我们看到其实它调用的是
this
.public List selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public List selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
List result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
returnresult;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
这里已经比较复杂了,必须通过debug来领会代码的含义:
从这段代码中我们可以看到,mybatis默认是会缓存结果集的:
由于有缓存这个方法就直接看最后一段:
接下来就快到了JDBC的代码了:
public List<Object> handleResultSets(Statement stmt) throws SQLException {
finalList<Object> multipleResults = new ArrayList<Object>();
finalList resultMaps = mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
int resultSetCount = 0;
ResultSet rs = stmt.getResultSet();
while (rs == null) {
// move forward to get the first resultset in case the driver// doesn't return the resultset as the first result (HSQLDB 2.1)if (stmt.getMoreResults()) {
rs = stmt.getResultSet();
} else {
if (stmt.getUpdateCount() == -1) {
// no more results. Must be no resultsetbreak;
}
}
}
validateResultMapsCount(rs, resultMapCount);
while (rs != null && resultMapCount > resultSetCount) {
final ResultMap resultMap = resultMaps.get(resultSetCount);
ResultColumnCache resultColumnCache = new ResultColumnCache(rs.getMetaData(), configuration);
handleResultSet(rs, resultMap, multipleResults, resultColumnCache);
rs = getNextResultSet(stmt);
cleanUpAfterHandlingResultSet();
resultSetCount++;
}
return collapseSingleResultList(multipleResults);
}
resultHandler这里可以对结果集进行自定义的操作,也可以自己实现一个resultHandler覆盖这个里的resultHandler:
这里按实体类的属性类型获取值:
好了,今天先分析到这里,谢谢大家!