简介
从mybatis的包,可以看出,它是一个ORM框架:
- 解决了jdbc相关的衔接,比如数据连接池、数据集的解释,数据库事务;
- 也解决了数据集到对象的映射;
- 另包括日志,以及对以上各个环节的缓存支持等等辅助模块。
以会话的形态供外界调用。
应用
mybatis的类库从SqlSessionFactoryBuilder开始,需要读取一个符合标准的xml配置文件。文件内容主要包括environments(比如数据源data source等),mappers(对象到JDBC的映射)
SqlSessionFactoryBuilder根据data source设置创建sql session工厂,这个工厂初始化后能被反复调用。
常规的调用过程如下:
session工厂能反复打开session——>session获取mapper——>调用mapper里定义业务接口(通常就是SQL处理)——>关闭session。通常有一些公用方法可以抽象出来, 比如session的commit和close,因此可以用代理类将session和mapper通过InvocationHandler进行关联。
代码示例
以下示例展示mybatis同时采用多个数据源,实际应用就是读写分离或业务分库。
(1)添加mybatis的支持
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
(2)准备好数据库环境,更多Mysql环境搭建点这里
准备测试数据:
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'tao');
(3)程序开发
- 数据库配置信息文件db:
hd.jdbc.driverClassName=com.mysql.jdbc.Driver
hd.jdbc.url=jdbc:mysql://192.168.142.128:3306/test?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
hd.jdbc.username=root
hd.jdbc.password=dadyz30h
ho.jdbc.driverClassName=com.mysql.jdbc.Driver
ho.jdbc.url=jdbc:mysql://192.168.142.128:3306/test2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
ho.jdbc.username=root
ho.jdbc.password=dadyz30h
- Mybatis配置文件mybatis.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="db"/>
<environments default="HO">
<environment id="HD">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${hd.jdbc.driverClassName}" />
<property name="url" value="${hd.jdbc.url}" />
<property name="username" value="${hd.jdbc.username}" />
<property name="password" value="${hd.jdbc.password}" />
</dataSource>
</environment>
<environment id="HO">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${ho.jdbc.driverClassName}" />
<property name="url" value="${ho.jdbc.url}" />
<property name="username" value="${ho.jdbc.username}" />
<property name="password" value="${ho.jdbc.password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="UserMapper"/>
</mappers>
</configuration>
- 用户类:
public class User {
private int uid;
private String name;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return String.format("id:%d/name:%s", uid, name);
}
}
- 用户对象业务处理:
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface UserMapper extends Mapper{
@Insert("insert into user(name) values(#{name})")
public void insertUser(User user);
@Update("update user set name=#{name} where uid=#{uid}")
public void updateUser(User user);
@Select("select * from user where uid=#{id}")
public User getUserById(int id);
@Delete("delete from t_user where uid=#{id}")
public void deleteUser(int id);
}
- mappers接口类:
public interface Mapper {
}
- Mapper工厂类:
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.commons.io.IOUtils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public enum MapperFactory {
HD {
private SqlSessionFactory sqlSessionFactory;
@Override
public <T> T createMapper(Class<? extends Mapper> clazz) {
return createMapper(clazz, this);
}
@Override
protected void createSqlSessionFactory() {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, this.name());
}
@Override
public SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
},
HO {
private SqlSessionFactory sqlSessionFactory;
@Override
public <T> T createMapper(Class<? extends Mapper> clazz) {
return createMapper(clazz, this);
}
@Override
protected void createSqlSessionFactory() {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, this.name());
}
@Override
public SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
};
/**
* Create a mapper of environment by Mapper class
* @param clazz Mapper class
* @param environment A datasource environment
* @return a Mapper instance
*/
public abstract <T> T createMapper(Class<? extends Mapper> clazz);
/**
* Create SqlSessionFactory of environment
*/
protected abstract void createSqlSessionFactory();
/**
* get SqlSessionFactory
*/
public abstract SqlSessionFactory getSqlSessionFactory();
private static InputStream inputStream = null;
static {
try {
inputStream = Resources.getResourceAsStream("mybatis.xml");
HO.createSqlSessionFactory();
inputStream = Resources.getResourceAsStream("mybatis.xml");
HD.createSqlSessionFactory();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(inputStream);
}
}
@SuppressWarnings("unchecked")
private static <T> T createMapper(Class<? extends Mapper> clazz, MapperFactory MapperFactory) {
SqlSession sqlSession = MapperFactory.getSqlSessionFactory().openSession();
Mapper mapper = sqlSession.getMapper(clazz);
return (T)MapperProxy.bind(mapper, sqlSession);
}
private static class MapperProxy implements InvocationHandler {
private Mapper mapper;
private SqlSession sqlSession;
private MapperProxy(Mapper mapper, SqlSession sqlSession) {
this.mapper = mapper;
this.sqlSession = sqlSession;
}
private static Mapper bind(Mapper mapper, SqlSession sqlSession) {
return (Mapper) Proxy.newProxyInstance(mapper.getClass().getClassLoader(),
mapper.getClass().getInterfaces(), new MapperProxy(mapper, sqlSession));
}
/**
* execute mapper method and finally close sqlSession
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
try {
object = method.invoke(mapper, args);
sqlSession.commit();
} catch(Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
return object;
}
}
}
注意mapper工厂类的写法,利用枚举解藕data source name,session factory的引用更加独立和简便。
- 调用类:
public class T {
/**
* @param args
*/
public static void main(String[] args) {
UserMapper mapper = MapperFactory.HD.createMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
user.setName("tao_new");
UserMapper mapper_new = MapperFactory.HD.createMapper(UserMapper.class);
System.out.println(user);
mapper_new.updateUser(user);
//--------------
UserMapper mapper2 = MapperFactory.HO.createMapper(UserMapper.class);
User user2 = mapper2.getUserById(1);
System.out.println(user2.getName());
}
}