简介
iBatis 是apache 的一个开源项目,一个O/R Mapping 解决方案,iBatis 最大的特点就是小巧,上手很快。如果不需要太多复杂的功能,iBatis 是能够满足你的要求又足够灵活的最简单的解决方案,现在的 iBatis 已经改名为 Mybatis
与 Hibernate 相比 iBatis 是一个半自动化的 ORM 框架,它没有像 Hibernate 一样将对象和表映射起来,而是将对象和 SQL 语句映射起来。
处理流程
从上图可以看出 ibatis 将请求 Java Object(如 JavaBean、Map、基本类型、XML) 加上待执行的 SQL 语句映射成 MappedStatement,解析 MappedStatement 得到 SQL 和 Object 后 组装 ,接着通过 JDBC 查询得到结果后并组装成 Java Object 返回给程序。
具体流程:
(1)加载配置并初始化
触发条件:加载配置文件
处理过程:将 SQL 的配置信息加载成为一个个 MappedStatement 对象(包括了传入参数映射配置、执行的 SQL 语句、结果映射配置),存储在内存中。
(2)接收调用请求
触发条件:调用 Mybatis 提供的API
传入参数:为 SQL 的 ID 和传入参数对象
处理过程:将请求传递给下层的请求处理层进行处理。
(3)处理操作请求
触发条件:API 接口层传递请求过来
传入参数:为 SQL 的 ID 和传入参数对象
处理过程:
- 根据 SQL 的 ID 查找对应的 MappedStatement 对象。
- 根据传入参数对象解析 MappedStatement 对象,得到最终要执行的 SQL 和执行传入参数。
- 获取数据库连接,根据得到的最终 SQL 语句和执行传入参数到数据库执行,并得到执行结果
- 根据 MappedStatement 对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
- 释放连接资源。
- 返回处理结果将最终的处理结果返回。
架构
- API 接口层:提供给外部使用的接口 API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
- 数据处理层:负责具体的 SQL 查找、SQL 解析、SQL 执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
- 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。
例子:
现有一 APP 中需要对联系方式 Contact 执行 ACID 操作,Contact 包括姓名、性别、电话、地址。我们通过 Spring 和 ibatis 来操控它。
数据库表如下图:
通过 Maven 配置依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.ourpointeer</groupId>
<artifactId>Contact</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- http://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependencies>
<!-- http://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<!-- http://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<!-- http://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
<!-- http://mvnrepository.com/artifact/org.apache.ibatis/ibatis-sqlmap -->
<dependency>
<groupId>org.apache.ibatis</groupId>
<artifactId>ibatis-sqlmap</artifactId>
<version>2.3.4.726</version>
<scope>compile</scope>
</dependency>
<!-- http://mvnrepository.com/artifact/com.ibatis/ibatis2-common -->
<dependency>
<groupId>com.ibatis</groupId>
<artifactId>ibatis2-common</artifactId>
<version>2.1.7.597</version>
</dependency>
<!-- http://mvnrepository.com/artifact/org.apache.ibatis/ibatis-core -->
<dependency>
<groupId>org.apache.ibatis</groupId>
<artifactId>ibatis-core</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.14</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!--bonecp 连接池-->
<dependency>
<groupId>com.jolbox</groupId>
<artifactId>bonecp</artifactId>
<version>0.7.1.RELEASE</version>
</dependency>
<!--slf4j 系统日志-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.0.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<!-- http://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
<repositories>
<repository>
<releases>
<updatePolicy>always</updatePolicy>
</releases>
<snapshots>
<updatePolicy>always</updatePolicy>
</snapshots>
<id>Jolbox</id>
<name>Jolbox Repositories</name>
<url>http://jolbox.com/bonecp/downloads/maven</url>
</repository>
</repositories>
</project>
联系人方式类:
联系人方式类 field 和数据库表字段是一一对应的。
public class Contact {
private Long id;
private String name;
private String gender;
private String mobile;
private String address;
public void setAddress(String address) {
this.address = address;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setName(String name) {
this.name = name;
}
public void setId(Long id) {
this.id = id;
}
public Contact() {
super();
}
public Contact(String name, String gender, String mobile, String address) {
this.name = name;
this.mobile = mobile;
this.gender = gender;
this.address = address;
}
@Override
public String toString() {
return "Contact{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
", mobile='" + mobile + '\'' +
", address='" + address + '\'' +
'}';
}
}
DAO 类:
public class BaseDAO {
/* Spring 对 ORM 提供支持,包括对 ibatis 提供的带有增删改查操作的模板
* 内部实际上是对 ibatis SqlMapClient 的封装
*/
private SqlMapClientTemplate sqlMapClientTemplate;
public SqlMapClientTemplate getSqlMapClientTemplate() {
return sqlMapClientTemplate;
}
public void setSqlMapClientTemplate(
SqlMapClientTemplate sqlMapClientTemplate) {
this.sqlMapClientTemplate = sqlMapClientTemplate;
}
}
DAO 接口:
public interface ContactDAO {
/* 联系人 DAO 提供对 contact 的操作 */
public Contact getContactById(Map<Object, Object> parameterMap);
public int insertContact(Contact contact);
public int updateContact(Contact contact);
}
DAO 实现类:
public class ContactDAOImpl extends BaseDAO implements ContactDAO {
public Contact getContactById(Map<Object, Object> paramenterMap) {
return (Contact) getSqlMapClientTemplate().queryForObject("getContactById", paramenterMap);
}
public int insertContact(Contact contact) {
return getSqlMapClientTemplate().update("insertContact", contact);
}
public int updateContact(Contact contact) {
return getSqlMapClientTemplate().update("updateContact", contact);
}
}
传入参数为 Map 对象:
public class ParameterMap extends HashMap<Object, Object> {
private static final long serialVersionUID = 1L;
/*
* 使我们可以通过如 Name, XXX, gender, XXX 形式来组装 Map */
public ParameterMap(Object... parameters) {
for (int i = 0; i < parameters.length - 1; i += 2) {
super.put(parameters[i], parameters[i + 1]);
}
}
}
Service 类:
public class ContactService {
private ContactDAO contactDAO;
public ContactDAO getContactDAO() {
return contactDAO;
}
public void setContactDAO(ContactDAO contactDAO) {
this.contactDAO = contactDAO;
}
public Contact getContactById(long id) {
Map<Object, Object> parameterMap = new ParameterMap("ID", id);
return getContactDAO().getContactById(parameterMap);
}
public int insertContact(Contact contact) {
return getContactDAO().insertContact(contact);
}
public int updateContact(Contact contact) {
return getContactDAO().updateContact(contact);
}
}
测试类:
public class App {
private static final Logger logger = (Logger) LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
// 查询操作
// ContactService contactService = (ContactService) context
// .getBean("contactService");
// Contact contact = contactService.getContactById(1);
// System.out.println(contact.toString());
//
// 插入操作
// ContactService contactService = (ContactService) context.getBean("contactService");
// Contact contact = new Contact("Tom", "male", "188222222", "Dalian");
// int recordInsertNum = contactService.insertContact(contact);
// System.out.println(recordInsertNum);
// 更新操作
ContactService contactService = (ContactService) context.getBean("contactService");
Contact contact = contactService.getContactById(1);
System.out.println(contact);
contact.setAddress("hehehehehehehe");
contactService.updateContact(contact);
}
}
Spring 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="wangweihao123" />
<property name="maxConnectionsPerPartition" value="30" />
<property name="minConnectionsPerPartition" value="10" />
<property name="partitionCount" value="3" />
<property name="acquireIncrement" value="5" />
<property name="statementsCacheSize" value="100" />
<property name="releaseHelperThreads" value="3" />
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="sqlMapConfig.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<constructor-arg>
<ref bean="sqlMapClient" />
</constructor-arg>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<bean id="baseDAO" class="org.ourpoineer.contact.common.BaseDAO">
<property name="sqlMapClientTemplate" ref="sqlMapClientTemplate" />
</bean>
<bean id="contactDAO" class="org.ourpoineer.contact.dao.impl.ContactDAOImpl"
parent="baseDAO" />
<bean id="contactService" class="org.ourpoineer.contact.service.ContactService">
<property name="contactDAO" ref="contactDAO" />
</bean>
</beans>
ibatis 配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings cacheModelsEnabled="true" enhancementEnabled="true"
lazyLoadingEnabled="true" errorTracingEnabled="true" maxRequests="32"
maxSessions="10" maxTransactions="5" />
<sqlMap resource="contact.xml" />
</sqlMapConfig>
sqlMap 配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap>
<typeAlias alias="parameterMap" type="org.ourpoineer.contact.common.ParameterMap" />
<typeAlias alias="contact" type="org.ourpoineer.contact.bean.Contact" />
<select id="getContactById" parameterClass="parameterMap"
resultClass="contact">
select *
from contact
where ID=#ID:LONG#
</select>
<!--id 相当于给 sqlmap 对象起了个名字-->
<!--该方式是以bean的方式实现,name,gender,mobile都要和bean对应-->
<insert id="insertContact" parameterClass="contact">
INSERT INTO
contact(NAME, GENDER, MOBILE, ADDRESS)
VALUES
(#name:VARCHAR#, #gender:VARCHAR#, #mobile:VARCHAR#, #address:VARCHAR#)
</insert>
<update id="updateContact" parameterClass="contact">
UPDATE contact
set NAME=#name:VARCHAR#, GENDER=#gender:VARCHAR#, MOBILE=#mobile:VARCHAR#, ADDRESS=#address:VARCHAR#
WHERE ID=#id:INT#
</update>
</sqlMap>
参考: