本文目標:
- 使用純Mybatis框架獲取數據;
- 理清Mybatis的工作過程。
創建項目並運行
首先創建maven項目,過程不再贅述。依賴如下:
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
</dependencies>
下面準備一張表:
CREATE TABLE `clips` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`content` varchar(256) NOT NULL DEFAULT '' COMMENT '內容',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '刪除標識:0正常,1刪除',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='clips';
添加一條數據:
對應的實體類:
public class ClipsEntity {
private Integer id;
private String content;
private Integer deleted;
private LocalDateTime createTime;
private LocalDateTime updateTime;
// 省略getter和setter
}
DAO:
public interface ClipsDAO {
ClipsEntity selectById(@Param("id") Integer id);
}
mapper文件:
<?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="com.chunrun.dao.ClipsDAO">
<select id="selectById" resultType="com.chunrun.entity.ClipsEntity">
select * from clips where id = #{id}
</select>
</mapper>
Mybatis配置文件:
<?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>
<settings>
<!--使用jdbc的getGeneratekeys獲取自增主鍵值-->
<setting name="useGeneratedKeys" value="true"/>
<!--使用列別名替換別名 默認true-->
<setting name="useColumnLabel" value="true"/>
<!--開啓駝峯命名轉換Table:create_time到 Entity(createTime)-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 打印查詢語句 -->
<setting name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl" />
</settings>
<typeAliases>
<typeAlias alias="ClipsEntity" type="com.chunrun.entity.ClipsEntity"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/bizu"/>
<property name="username" value="chunrun"/>
<property name="password" value="chunrun1s"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/ClipsDAO.xml"/>
</mappers>
</configuration>
下面寫個測試:
public class Main {
public static void main(String[] args) {
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
ClipsDAO clipsDAO = session.getMapper(ClipsDAO.class);
ClipsEntity clipsEntity = clipsDAO.selectById(1);
System.out.println(clipsEntity);
} catch (Exception e) {
System.out.println(e);
}
}
}
運行結果:
運行成功。
那麼,在這個過程中,程序具體做了什麼事呢?一步一步來看。
首先,我們用配置文件生成了一個InputStream;然後用InputStream生成了生成SqlSessionFactory;然後獲取Session;獲取對應的mapper,執行SQL獲取結果。Mybatis做的事情主要有三步:
- 從配置文件中生成SqlSessionFactory;
- 從SqlSessionFactory中獲取session;
- 獲取對應的mapper,執行SQL。
下面逐步看源碼。
加載mybatis配置,生成SqlSessionFactory
// 首先調用的是這個方法:
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
// 然後是這個:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 根據參數獲取一個XMLConfigBuilder,這部分是重點
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.
}
}
}
// 返回的build方法如下,可以看出實現是DefaultSqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
註釋部分已經很清楚了,下面重點看下XMLConfigBuilder,Mybatis通過這個類來解析mybatis對應的配置。
// 解析configuration節點下面的子節點,並返回最終的配置。
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
// 加載properties節點下的屬性,
propertiesElement(root.evalNode("properties"));
// 加載settings節點下的屬性
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
// 加載別名配置
typeAliasesElement(root.evalNode("typeAliases"));
// 加載插件配置
pluginElement(root.evalNode("plugins"));
// 加載objectFactory配置
objectFactoryElement(root.evalNode("objectFactory"));
// 加載objectWrapperFactory配置
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 加載reflectorFactory配置
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
// 加載environment配置,這裏會配置事務管理器
environmentsElement(root.evalNode("environments"));
// 加載databaseIdProvider配置
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
// 加載typeHandler是配置,自定義的typeHandler會在這注冊
typeHandlerElement(root.evalNode("typeHandlers"));
// 加載mapper配置
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
至此,mybatis配置加載完成。
小結
本文主要介紹瞭如何使用純Mybatis操作數據庫,然後介紹了Mybatis加載配置的過程。內容相對粗淺,深入分析在下文。