前言
本文整理一下MyBatis的基本使用,這裏非工作中使用的場景,主要爲了分析源碼而做準備
預備數據庫
如果你使用docker的話,推薦看看我的文章把 [Docker 實戰系列 - MySQL環境](…/…/Docker/實戰系列/Docker 實戰系列 - MySQL環境.md)
創建數據庫
# 創建庫
create database mybatis_demo;
創建表
CREATE TABLE `student` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`cls_id` int(10) NOT NULL COMMENT '班級ID',
`name` varchar(32) NOT NULL COMMENT '名字',
`age` int(3) NOT NULL COMMENT '年齡',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
CREATE TABLE `cls` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '班級名稱',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
插入測試數據
INSERT INTO `student`(`id`, `cls_id`, `name`, `age`, `create_time`) VALUES (1, 1, '張三', 13, now());
INSERT INTO `student`(`id`, `cls_id`, `name`, `age`, `create_time`) VALUES (2, 2, '李四', 14, now());
INSERT INTO `cls`(`id`, `name`, `create_time`) VALUES (1, '初一1班', now());
INSERT INTO `cls`(`id`, `name`, `create_time`) VALUES (2, '初一2班', now());
創建項目
在上文中已經創建好了mybatis的源碼環境,現在我們開始創建自己的項目
設置自己的包名,我爲了以後複習所以用了 chapter1
準備工作
配置properties文件
vim application.properties
jdbc.driver=com.mysql.jdbc.Driver
default.environment=dev
全局配置
vim mybatis-config.xml
屬性配置優先級
- build方式
- 外部的 properties 文件
- xml配置的properties
<?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>
<!-- 這裏只是演示,正常你使用 app.properties 配置即可 -->
<properties resource="application.properties">
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
</properties>
<!-- 如果需要遠程加載的話可以使用url 只能選一種-->
<!-- <properties url=""> -->
<environments default="${default.environment}">
<!-- 測試環境 -->
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="jdbc:mysql://localhost/mybatis_demo"/>
<property name="username" value="root"/>
<property name="password" value="a123456"/>
</dataSource>
</environment>
<!-- 生產環境 -->
<environment id="pro">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="jdbc:mysql://192.168.160.130/mybatis_online"/>
<property name="username" value="root"/>
<property name="password" value="Aa123456"/>
</dataSource>
</environment>
</environments>
<mappers>
...
</mappers>
</configuration>
定義 Student 並使用 lombok [Lombok 的使用](…/…/Java/編程技巧/Lombok 的使用.md)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer id;
private Integer clsId;
private String name;
private Date createTime;
}
現在項目結構
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── xm
│ │ └── chapter1
│ │ ├── MainTest.java
│ │ ├── Student.java
│ │ └── StudentMapper.xml
│ └── resources
│ ├── application.properties
│ └── mybatis-config.xml
└── test
└── java
XML方式
自定義Mapper.xml
vim StudentMapper.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="com.xm.chapter1.StudentMapper">
<select id="selectStudentXml" resultType="com.xm.chapter1.Student" >
select * from student where id = #{id}
</select>
</mapper>
修改全局配置的mapper,並引入我們的文件
vim mybatis-config.xml
<configuration>
...
<mappers>
<mapper resource="com/xm/chapter1/StudentMapper.xml"/>
</mappers>
</configuration>
運行
public class MainTest {
private SqlSession session;
@Before
public void init() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession(true);
}
@Test
public void test1() throws IOException {
// 通過xml查詢
Student result = session.selectOne(
"com.xm.chapter1.StudentMapper.selectStudentXml", 1);
System.out.println(result.toString());
}
}
對於結果的轉移,不知道你有沒有發現兩個字段(createTime,clsId)爲空,我們來修改一下
<?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.xm.chapter1.StudentMapper">
<resultMap id="StudentMap" type="com.xm.chapter1.Student">
<id property="id" column="id"/>
<result property="clsId" column="cls_id"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="selectStudentXml" resultMap="StudentMap" >
select * from student where id = #{id}
</select>
</mapper>
接口方式
爲了避免混淆,可以先把上面的xml刪除,或者不刪除屏蔽掉下面的即可
修改全局配置,引入接口方式
<configuration>
...
<mappers>
<mapper class="com.xm.chapter1.StudentMapper"/>
</mappers>
</configuration>
創建mapper接口
public interface StudentMapper {
@Select("select * from student where id = #{id}")
Student selectInterface(Integer id);
}
運行
public class MainTest {
....
@Test
public void test2(){
StudentMapper mapper = session.getMapper(StudentMapper.class);
Student student = mapper.selectInterface(1);
System.out.println(student);
}
}
對於結果的轉移,不知道你有沒有發現兩個字段(createTime,clsId)爲空,我們來修改一下
public interface StudentMapper {
@Select("select id,name,cls_id as clsId,create_time as createTime from student where id = #{id}")
Student selectInterface(Integer id);
}
類型處理器
持久層框架其中比較重要的工作就是處理數據的映射轉換,把java 類型轉換成jdbc 類型的參數,又需要把jdbc 類型的結果集轉換成java 類型。
public interface TypeHandler<T> {
void setParameter(
PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
我們將上面的student的事件類型,修改爲long試下
...
public class Student {
private Integer id;
private String name;
private Integer clsId;
// 改這裏
private Long createTime;
}
運行後發現結果不符合我們預期
Student(id=1, name=張三, clsId=1, createTime=2019)
自定義TypeHandler解決這個問題
public class LongTimeHandler extends BaseTypeHandler<Long> {
@Override
public void setNonNullParameter(
PreparedStatement ps, int i, Long parameter, JdbcType jdbcType) throws SQLException {
ps.setDate(i, new Date(parameter));
}
@Override
public Long getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getDate(columnName).getTime();
}
@Override
public Long getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getDate(columnIndex).getTime();
}
@Override
public Long getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getDate(columnIndex).getTime();
}
}
全局配置的方式 - 任選一
<configuration>
<typeHandlers>
<typeHandler handler="com.xm.chapter1.LongTimeHandler"
javaType="long" jdbcType="TIMESTAMP" />
</typeHandlers>
</configuration>
// 如果嫌棄上面寫 javaType、jdbcType 麻煩,可以使用註解
@MappedJdbcTypes(JdbcType.TIMESTAMP)
@MappedTypes(Long.class)
public class LongTimeHandler extends BaseTypeHandler<Long> {
....
}
針對單個返回值 - 任選一
<mapper namespace="com.xm.chapter1.StudentMapper">
<resultMap id="StudentMap" type="com.xm.chapter1.Student">
...
<result property="createTime"
column="create_time" typeHandler="com.xm.chapter1.LongTimeHandler"/>
</resultMap>
....
</mapper>
返回結果
Student(id=1, name=張三, clsId=1, createTime=1562342400000)
日誌
創建文件
vim resources/log4j.properties
log4j.properties
### 設置日誌級別 ###
log4j.rootLogger = debug,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c:%L - %m%n