Every MyBatis application centers around aninstance of SqlSessionFactory. A SqlSessionFactoryinstance can be acquired by using the SqlSessionFactoryBuilder.
SqlSessionFactoryBuildercan builda SqlSessionFactoryinstance from an XML configuration file, of from a custom prepared instance ofthe Configuration class.
这是MyBatis使用文档2.1中的内容。他讲述了SqlSessionFactory的至关重要的地位,就如同Hibernate的SessionFactory。它存在一个工厂类:SqlSessionFactoryBuilder。SqlSessionFactory能够通过工厂构造类实例化。如同Hibernate的SessionFactory,它的创建可以通过传统的ConfigurationClass类也可以通过XML配置文件进行。
通过XML创建SqlSessionFactory
为了更好的具体了解,我们先创建一些列的文件结构,如下图所示:
这些文件结构是根据MVC的设计模式来进行的,dao层是对数据库的访问层,service是业务逻辑层,而proxy是对service的代理,其中最重要的是SessionManager,而proxy则是用这个SessionManger类创建产生的SqlSessionFactory开启SqlSession,将SqlSession传递给Service,接着Service传递给Dao层的Impl实现类来具体操作数据库。之后在Proxy类中关闭数据流,即SqlSession。
将mybatis提供的xml复制到mybatis-config.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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml" />
</mappers>
</configuration>
可以看出,上面的配置文件并不完善,不过mybatis未做解释,继续向下。
MyBatis提供了XML方式和非XML方式创建SqlSessionFactory,而我们现在将的 是XML的方式,当然是通过这个方式了。
进行SessionManager的编写:
package net.mybatis.manager;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class SessionManager {
//default xml path
private static String resource = "mybatis-config.xml";
private static SqlSessionFactory sqlSessionFactory;
public static SqlSessionFactory getFactory() throws IOException{
InputStream inputStream = Resources.getResourceAsStream(resource);
return (sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream));
}
public static String getResource() {
return resource;
}
public static void setResource(String resource) {
SessionManager.resource = resource;
}
public SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
}
我在这个SessionManager的类中提供了getSqlSessionFactory的方法,Proxy代理类可以通过这个方法通过openSession来获取到SqlSession。
我采用的是自下向上的编写方式。因此,接下来对User进行编码(因为只是进行测试,所以User中只有一个name的属性):
package net.mybatis.model;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接下来,定义数据库操作的接口IUserDao(这里我定义了一个getUsers的方法):
package net.mybatis.dao;
import java.util.List;
import net.mybatis.model.User;
public interface IUserDao {
public List<User> getUsers();
}
定义了接口的方法,那么就要有个具体的实现类:
package net.mybatis.dao.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import net.mybatis.dao.IUserDao;
import net.mybatis.model.User;
public class UserDaoImpl implements IUserDao{
private SqlSession session;
public UserDaoImpl(SqlSession sqlSession){
this.session = sqlSession;
}
@Override
public List<User> getUsers() {
return null;
}
}
因为我们不知道MyBatis如何通过session来具体操控数据库,所以现在先放置在一边。
另外,我们需要SqlSession来进行数据库的操作,因此,要在IUserDao接口实例化的时候,传进来SqlSession这个参数,以此操控数据库。
接下来是业务逻辑层的接口定义:
package net.mybatis.service;
import java.util.List;
import net.mybatis.model.User;
public interface IUserService {
public List<User> getUsers();
}
接着是业务逻辑层的具体实现:
package net.mybatis.service.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import net.mybatis.dao.IUserDao;
import net.mybatis.dao.impl.UserDaoImpl;
import net.mybatis.model.User;
import net.mybatis.service.IUserService;
public class UserServiceImpl implements IUserService{
private IUserDao dao;
public UserServiceImpl(SqlSession sqlSession){
this.dao = new UserDaoImpl(sqlSession);
}
@Override
public List<User> getUsers() {
return this.dao.getUsers();
}
}
Service层的实现是通过IUserDao层的实例化,传入SqlSession,通过调用dao层的getUsers方法来获取数据库操控结果。
因为所有的Session是由Proxy进行代理的,所以,我们仍旧是通过构造函数传入一个SqlSession,这样也有利于减少耦合。
接下来最为重要,是Proxy的编写,所有的业务处理都通过该类来调用实现:
package net.mybatis.proxy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import net.mybatis.manager.SessionManager;
import net.mybatis.model.User;
import net.mybatis.service.IUserService;
import net.mybatis.service.impl.UserServiceImpl;
public class UserProxy {
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
private IUserService service;
public UserProxy(){
try {
this.sqlSessionFactory = SessionManager.getFactory();
} catch (IOException e) {
e.printStackTrace();
}
this.sqlSession = this.sqlSessionFactory.openSession();
this.service = new UserServiceImpl(this.sqlSession);
}
public List<User> getUsers() throws Exception{
List<User> users = new ArrayList<User>();
try{
users = this.service.getUsers();
}catch(Exception e){
throw e;
}finally{
this.sqlSession.close();
}
return users;
}
}
接下来是MyBatis提供了两种方式操控数据库,第一种是session.selectOne这种直接通过SqlSession来操作的,另一种是通过一个接口文件,该类文件通常被以Mapper命名解为,比如UserMapper,这类方式,通过接口文件中的接口方法来进行调用操作。
MyBatis对这两种方式做了一定的解释。
这两种方式,都可以通过XML或者Annotation的方式定义。
首先是XML的方式:
我们先前复制了简单的mybatis.xml文件,现在我们将其中的<mapper>标签:
<mappers>
<mapper resource="org/mybatis/example/BlogMapper.xml" />
</mappers>
更改为:
<mapper namespace="net.mybatis.mapper.UserMapper">
<select id="selectUser" resultType="List">
select * from User
</select>
</mapper>
很明显的可以看出这些标签的意思:mapper中的namespace是用来标识Mapper这类的联系文件的。而<select>标签则是用来描述SQL语句,id为方法的方法名,resultType为方法的返回类型,我们这里是List<User>,自然的也有参数类型:parameterType。因为我们没有参数,所以,这里不需要填写参数类型。
写一个测试类,net.mybatis.test.Test:
package net.mybatis.test;
import net.mybatis.proxy.UserProxy;
public class Test {
public static void main(String []args) throws Exception{
UserProxy proxy = new UserProxy();
System.out.println(proxy.getUsers());
}
}
并且将UserDaoImpl中的getUsers的方法进行修改:
@Override
public List<User> getUsers() {
List<User> users = this.session.selectList("net.mybatis.mapper.UserMapper.selectUser");
return users;
}
右击运行,出现:
Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 17; columnNumber: 52; 必须为元素类型 "mapper" 声明属性 "namespace"。
的错误。
这是什么原因?
仔细阅读文档,发现文档一开始所描述的与之后的Configuration XML的章节中,配置的有出入,不知道是不是之前的方法过时的缘故还是什么原因,暂时未找到原因,而根据后面文档的配置,则是可以成功运行,那么我们就以之后文档的描述来进行设置。
之前的的问题找到原因了。是因为没有将mapper另外独立出来,MyBatis在config配置文件中不允许直接使用mapper中的select等操作,需要新建立一个xml文件user.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="net.mybatis.mapper.UserMapper">
<select id="selectUser" resultType="net.mybatis.model.User">
select * from user
</select>
</mapper>
可以看到,它的DOCTYPE为Mapper,而之前的config配置文件为Config,这个也就是为什么会出现之前问题的原因。
但是因为MyBatis不能够返回一个List,它只能返回基础类型,List的返回是通过集合中的元素类型来决定返回类型的。
将mybatis-cofing文件中的<mappers>改为:
<mappers>
<mapper resource="net/mybatis/mapper/user.mapper.xml"/>
</mappers>
将UserMapper更改为:
package net.mybatis.mapper;
import java.util.List;
import net.mybatis.model.User;
public interface UserMapper {
public List<User> selectUser();
}
将UserDaoImpl更改为:
package net.mybatis.dao.impl;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import net.mybatis.dao.IUserDao;
import net.mybatis.model.User;
public class UserDaoImpl implements IUserDao{
private SqlSession session;
public UserDaoImpl(SqlSession sqlSession){
this.session = sqlSession;
}
@Override
public List<User> getUsers() {
List<User> users = this.session.selectList("net.mybatis.mapper.UserMapper.selectUser");
return users;
}
}
运行后的结果:
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.
[net.mybatis.model.User:[name:aa], net.mybatis.model.User:[name:dd]]
可以看到,数据库的数据已经查了出来。