1.MyBatis的基本构成
- SqlSessionFactoryBuilder(构造器)
它会根据配置信息或者代码生成SqlSessionFactory(工厂接口)
- SqlSessionFactory
依靠工厂来生成SqlSession 会话
- SqlSession
是一个既可以发送 SQL去执行并返回结果,也可以获取Mapper的接口
- SQL Mapper
它是MyBatis新设计的组件,它是由一个Java接口和Xml文件(或者注解)构成的,需要给出对应的SQL和映射规划。它负责发送SQL去执行,并返回接口
2.构建SqlSessionFactory
每个MyBatis的应用都是以SqlSessionFactory的实例为中心。SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder获得。
- SqlSessionFactory是接口类
public interface SqlSessionFactory {
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();
}
SqlSessionFactory的任务是创建SqlSession。
SqlSession是类似一个JDBC的Connection对象。
- JBDC的Connection的作用
private Connection getConnection() throws ClassNotFoundException, SQLException {
Connection connection = null;
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mybatis";
String user = "root";
String password = "root";
connection = DriverManager.getConnection(url, user, password);
return connection;
}
2.1 MyBatis的构建代码
public static void main(String[] args) throws IOException {
//读取mybatis-config.xml文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//初始化mybatis,创建SqlsessionFactory类的实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//创建Sqlsession实例
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取User Dao的实例
UserDao dao = sqlSession.getMapper(UserDao.class);
User user = dao.getUser(1);
System.out.println(user.toString());
}
从上面的代码可以看出,build方法是真正创建SqlSessionFactory的核心代码
- build方法
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
- parse()方法
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
parse方法就是读取xml的信息,并将xml的信息写入到org.apache.ibatis.session.Configuration实例对象中。而这个对象是存在于整个MyBatis应用的生命周期中,以便重复读取和运用。
2.2 SqlSessionFactory的实现类
- 1.SqlSessionManager
- 2.DefaultSqlSessionFactory
3.构建方式
3.1 使用xml方式构建
- 1.定义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>
<!--定义别名-->
<typeAliases>
<typeAlias type="model.User" alias="user"/>
</typeAliases>
<!--定义数据库信息-->
<!--默认使用id为mysqldata的数据库作为应用程序的开发数据库-->
<environments default="mysqldata">
<environment id="mysqldata">
<!--采用jdbc事务管理-->
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
<!--定制映射器-->
<mappers>
<mapper resource="mapper/UserDao.xml" />
</mappers>
</configuration>
- 2.定义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="dao.UserDao">
<select id="getUser" parameterType="int" resultType="user">
select * from tb_user where id=#{id};
</select>
</mapper>
这个文件我们在mybatis-config.xml中配置了,所以MyBatis会读取这个配置文件,生成映射器
这里的命名空间名称与持久层的接口的名称一致
用一个select元素定义了一个查询SQL,id为getUser。这需要跟下面的持久层接口名称一致。并且参数类型也必须与持久层的参数一样。这里返回的参数为user。这个是别名我们在mybatis-config.xml里面定义的。
- 3.定义持久层接口
public interface UserDao {
User getUser(int id);
}
- 4.客户端调用
public class MyBatisClient {
public static void main(String[] args) throws IOException {
//读取mybatis-config.xml文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//初始化mybatis,创建SqlsessionFactory类的实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//创建Sqlsession实例
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取User Dao的实例
UserDao dao = sqlSession.getMapper(UserDao.class);
User user = dao.getUser(1);
System.out.println(user.toString());
}
}
映射器的功能就是提供SQL和SQL对POJO的映射规则定义。
3.2 使用代码方式构建
除了使用xml的配置的方式创建代码外,也可以使用Java编码来实现。不过当我们在需要修改环境的时候,我们需要重新编译代码,不利于维护。
- 1.定义Java代码映射器
public interface UserDaoJavaCode {
@Select("select * from tb_user where id=#{id}")
User getUser(int id);
}
{id}为这条SQL的请求参数。因为定义的实体名称与数据库的属性名称一样。那么MyBatis就会把这条语句的查询结果自动映射到我们需要的POJO属性上。
Java实体上注解的SQL语句与xml上的SQL没有差别,但是如果SQL复杂的话,使用xml来描述SQL语句远比在Java实体上方便。
- 2.客户端调用及注册MyBatis环境信息
public class MyBatisCodeClient {
public static void main(String[] args) {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//创建Sqlsession实例
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取User Dao的实例
UserDaoJavaCode dao = sqlSession.getMapper(UserDaoJavaCode.class);
User user = dao.getUser(1);
System.out.println(user.toString());
}
private static PooledDataSource getDataSource() {
PooledDataSource dataSource = new PooledDataSource();
dataSource.setDriver("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
private static SqlSessionFactory getSqlSessionFactory() {
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, getDataSource());
Configuration configuration = new Configuration(environment);
configuration.getTypeAliasRegistry().registerAlias("user", User.class);
configuration.addMapper(UserDaoJavaCode.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
return sqlSessionFactory;
}
}
3.3 使用"命名空间(namespace)+SQL id"获取数据
这种方式是MyBatis原始版本的iBatis的获取数据方式
- 使用getMapper获取数据对象
UserDao dao = sqlSession.getMapper(UserDao.class);
User user = dao.getUser(1);
System.out.println(user.toString());
- 使用原始获取数据方式
User user=sqlSession.selectOne("getUser",1);
System.out.println(user);
getUser为定义的SQL语句的id。如果SQL语句名称全局定义两个相同或更多,那么需要加上对应的包的名称
4.MyBatis的生命周期
4.1 SqlSessionFactoryBuilder
其作用是利用XML或者Java编码获取资源来构建SqlSessionFactory的。通过它可以构建多个SessionFactory。相当于一个构建器,一旦构建完成后,作用就消失。这时候我们应该回收它
4.2 SqlSessionFactory
其作用是创建SqlSession,而SqlSession就是一个会话,相当于JDBC的Connection对象。每次应用程序需要访问数据库,我们就要通过SqlSessionFactory创建SqlSession。
所以SqlSessionFactory的应该在MyBatis应用的整个生命周期内。而如果我们多次创建同一个数据库的SqlSessionFactory,每次创建SqlSessionFactory会打开更多的数据库连接(Connection)资源。所以应该使用单例模式去维护这个对象
4.3 SqlSession
SqlSession是一个会话,相当于JDBC的Connection对象,所以它的生命周期应该是在请求数据库处理事务的过程中。它是一个线程不安全的对象。在涉及多线程的时候需要特别注意。操作数据库需要注意其隔离级别,数据库锁等高级对象。
4.4 Mapper
Mapper是一个接口,没有实现任何实现类,它的作用是发送SQL,然后返回我们需要的结果,或者执行SQL从而修改数据库的数据。它应该在一个SqlSession事务方法之内。如同JDBC的一条SQL语句的执行。生命周期与SqlSession相同。
5.优化后的代码
- 1.新建一个SqlSessionFactoryUtil工具类,维护单例模型
package utils;
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.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SqlSessionFactoryUtil {
private static SqlSessionFactory sqlSessionFactory = null;
//类线程锁
private static final Class CLASS_LOCK = SqlSessionFactoryUtil.class;
/**
* 私有化构造函数
*/
private SqlSessionFactoryUtil() {
}
public static SqlSessionFactory inintSqlSessionFactory() {
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException ex) {
Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, null, ex);
}
synchronized (CLASS_LOCK) {
if (sqlSessionFactory == null)
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
return sqlSessionFactory;
}
public static SqlSession openSqlSession() {
if (sqlSessionFactory == null)
inintSqlSessionFactory();
return sqlSessionFactory.openSession();
}
}
- 2.调用客户端
import dao.UserDao;
import model.User;
import org.apache.ibatis.session.SqlSession;
import utils.SqlSessionFactoryUtil;
public class MyBatisOptimizeClient {
public static void main(String[] args) {
SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
UserDao userMapper = sqlSession.getMapper(UserDao.class);
User user = userMapper.getUser(1);
System.out.println(user);
}
}