1_框架概述
框架是一個半成品,已經對基礎的代碼進行了封裝并提供相應的API,開發者在使用框架時直接調用封裝好的api可以省去很多代碼編寫,從而提高工作效率和開發速度,框架是一種經過校驗、具有一定功能的半成品軟件.
經過校驗:指框架本身經過測試,且框架自身所具有的功能已經實現具有一定功能:指框架可以完成特定的功能,不同的框架功能不同
半成品軟件:指框架自身是一個軟件,但是該軟件無法直接運行,需要配合其他的程序才可以完成指定的工作.
框架的工作模式:
開發工程師建立在框架的基礎之上完成開發部分功能 加 框架自身完成部分功能組成一個完整的產品
2_MyBatis 基礎
2.1_MyBatis的概述
MyBatis 是一款優秀的持久層框架,它支持定制化?SQL、存儲過程以及高級映射。MyBatis?避免了幾乎所有的?JDBC 代碼和手動設置參數以及獲取結果集。MyBatis?可以使用簡單的?XML?或注解來配置和映射原生類型、接口和?Java 的?POJO(Plain Old Java Objects,普通老式?Java 對象)為數據庫中的記錄。
mybatis框架架構圖:
我們把Mybatis的功能架構分為三層:
- API接口層:提供給外部使用的接口API,開發人員通過這些本地API來操縱數據庫。接口層一接收到調用請求就會調用數據處理層來完成具體的數據處理。
- 數據處理層:負責具體的SQL查找、SQL解析、SQL執行和執行結果映射處理等。它主要的目的是根據調用的請求完成一次數據庫操作。
- 基礎支撐層:負責最基礎的功能支撐,包括連接管理、事務管理、配置加載和緩存處理,這些都是共用的東西,將他們抽取出來作為最基礎的組件。為上層的數據處理層提供最基礎的支撐。
2.2_環境準備
需求: 向用戶表中添加一條數據
- 添加項目需要的?jar 包
- lombok-1.16.6.jar(新的IDEA不用添加)
Lombok自動生成?getter/setter/toString 等方法使用的前提是已經在?idea 中安裝了?lombok 插件
- mysql-connector-java-5.1.26-bin.jar
MySQL 數據庫的?JDBC 驅動包,訪問?MySQL 必須導入備?jar 包
- mybatis-3.4.5.jar MyBatis 框架的核心?jar 包
- 創建一張用戶表:user
CREATE TABLE `user` (
`id` bigint(20) NOT?NULL?AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(255) DEFAULT NULL,
`salary` decimal(10,0) DEFAULT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2?DEFAULT CHARSET=utf8;
- 根據表結構創建實體類
@Getter@Setter@ToString
@NoArgsConstructor@AllArgsConstructor
public class User?{
private Long?id;
private String?name;
private Integer?age;
private BigDecimal salary;
private Date hiredate;
}
- mybatis主配置文件: mybatis-config.xml
- 在項目的resources(source folder)下創建mybatis-config.xml配置文件
- 拷貝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">
添加環境配置(事務管理器?/ 連接池?/ 映射文件)
<?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="dev">
<environment id="dev">
<!--
MyBatis 內置的事務管理器
JDBC:org.apache.ibatis.transaction.jdbc.JdbcTransaction的別名
-->
<transactionManager type="JDBC"/>
<!--
MyBatis 內置的連接池
POOLED:org.apache.ibatis.datasource.pooled.PooledDataSource的別名
-->
<dataSource type="POOLED">
<!--
driver:這是POOLED連接池對象的驅動類的屬性名,
Druid連接池對象的驅動類屬性名是driverClassName
-->
<property name="driver"?value="com.mysql.jdbc.Driver"/> <property name="url"?value="jdbc:mysql:///mybatis"/
<property name="username"?value="root"/>
<property name="password"?value="admin"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="cn/UserMapper.xml"/> </mappers>
</configuration>
- mapper 映射文件: UserMapper.xml
mybatis中,訪問數據庫的SQL語句是編寫在mapper配置文件中的,程序員按照這個文件約定的格式進行配置即可
中創建配置文件: UserMapper.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">
在配置文件中添加?SQL 語句
<!--
一個項目可以操作多張表
每張表都需要一個mapper配置文件來編寫SQL語句
每條SQL語句都需要有一個唯一的標識
這個唯一的標識由?namespace + sqlid 組成
使用下面的namespace+sqlid就得到了保存用戶信息的唯一標識:
insert 接下來,我們就可以使用上面的標識找到這條SQL語句了
-->
<mapper namespace="cn.UserMapper"> <insert id="insert">
insert into user(name,age,salary,hiredate)
values(#{name}, #{age}, #{salary}, #{hiredate})
</insert>
</mapper>
注意: 一定記得在?mybatis-config.xml 配置文件中關聯映射文件
<mappers>
<!--
這里是mapper文件的路徑,所以使用/分割
-->
<mapper resource="cn/UserMapper.xml"/> </mappers>
2.3_DAO層開發
- dao接口
創建?dao 接口: IUserDAO.java
public interface IUserDAO?{
/**
- 向user表中插入一條數據
- @param u 要插入的數據
?*/
void insert(User u);
}
- dao 接口實現類
創建?dao 的實現類: UserDAOImpl.java
按以下?API 實現數據的保存操作:
- SqlSessionFactory : 對連接池(DataSource)的封裝
SqlSession openSession() : 獲取SqlSession對象
- SqlSession,對連接(Connection)的封裝
int insert(String statementid, Object param);
statementid: 有mapper配置文件中的namespace+sqlid組成?void commit(): 提交事務
void close() : 釋放資源
- 調用?SqlSession 中的?insert 方法,執行指定的?SQL
public class UserDAOImpl?implements IUserDAO?{?public void?insert(User u) {
try {
InputStream in =?Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory fac =?new
SqlSessionFactoryBuilder().build(in);
SqlSession session =?fac.openSession();
session.insert("UserMapper.insert",
);
session.commit();
session.close();
} catch?(Exception e) {
e.printStackTrace();
}
}
}
在測試類中測試?insert 方法
public class UserDAOTest?{
private IUserDAO dao?=?new UserDAOImpl();
@Test
public void?testInsert() {
User u =?new?User(null,"張三",20,new?BigDecimal(20000),?new?Date());?dao.insert(u);
}
}
2.4_MyBatis 執行流程
- 加載主配置文件(mybatis-config.xml)到內存中,將數據封裝成對象Configuration/Environment/TransactionManager/DataSource等
- 通過操作拿到訪問數據庫的基本信息,根據這些數據創建?SqlSessionFactory 對象
- 從?SqlSessionFactory 對象中獲取到?SqlSession 對象,然后執行SQL
- INSERT INTO user(name,age,salary,hiredate) VALUES(#{name},#{age},#{salary},#{hiredate})
被翻譯成
INSERT INTO user(name,age,salary,hiredate)
VALUES(?, ?, ?, ?)
- 使用?PreparedStatement 來執行指定的SQL
從傳遞進來的?User 對象中依次獲取到?name/age/salary/hiredate這些屬性的值這里需要使用到內省機制來訪問對象中的屬性
注:
在加載完當前映射文件之后,會將SQL中的?#{} OGNL表達式翻譯成對應的占位符?,
執行上面的SQL,需要將數據設置給當前的語句對象?ps.setObect(1, 從參數中獲取到name屬性的值); ps.setObect(2, 從參數中獲取到age屬性的值); ps.setObect(3, 從參數中獲取到salary屬性的值); ps.setObect(4, 從參數中獲取到hiredate屬性的值);
操作步驟回顧:
- 創建項目,導入jar包
- 創建表和模型
3 創建?mybatis-config.xml 配置環境
4 創建?UserMapper.xml 文件 存在?mapper包中,配置sql語句
5 創建?dao 接口和實現類
6 啟動?MyBatis 去執行插入操作
- 測試插入操作
3_獲取插入數據生成的主鍵
在開發中,如果需要獲取到數據庫中自動生成的主鍵,那么使用?MyBatis 應該如何實現呢?
<insert id="insert"?useGeneratedKeys="true"?keyProperty="id"?keyColumn="id"> insert into user(name,age,salary,hiredate)
values(#{name}, #{age}, #{salary}, #{hiredate})
</insert>
useGeneratedKeys: 是否要獲取自動生成的主鍵
keyColumn: 表中的主鍵列
keyProperties: 主鍵列對應的屬性
表示從獲取哪個列的值封裝到哪個屬性中
通過上面的配置,在執行了保存操作后,mybatis 會自動將主鍵值封裝到傳遞進來的?User 對象的?id 屬性中
所以,此時的?User 對象的?id 屬性就有值了(在保存之前是沒有的)
parameterType : 參數類型,可以不用寫,由MyBatis自己通過用戶傳入的對象去推導.
4_更新和刪除操作
和保存操作的開發流程一致,在完成了保存操作之后,更新和刪除操作一樣可以實現?dao 中更新的實現
@Overrid
public void?update(User u) {
try {
InputStream in =?Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory fac =?new?SqlSessionFactoryBuilder().build(in);
SqlSession session =?fac.openSession();
session.update("UserMapper.update",?u);
session.commit();
session.close();
} catch?(Exception e) { e.printStackTrace();
}
}
更新在?mapper 中的?SQL
<update id="insert">
update user
set?name=#{name}, age = #{age}, salary = #{salary}, hiredate = #{hiredate} where
id = #{id}
</insert>
dao 中刪除的實現
@Override
public void?delete(long?id) {
try {
InputStream in =?Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory fac =?new?SqlSessionFactoryBuilder().build(in);
SqlSession session =?fac.openSession();
session.delete("UserMapper.delete",?id);
session.commit();
session.close();
} catch?(Exception e) { e.printStackTrace();
}
}
刪除在?mapper 中的?SQL
<delete id="delete">
delete from user where id = #{id}
</delete>
注意:
1 當傳入的只有一個普通類型(一個值)的時候#{} 中的名稱可以隨便寫,但是建議見名知義
2 不管使用的是?insert 方法還是?delete 方法,底層調用的還是update方法,通過sql語句來區別dml操作
5_查詢操作
根據?id 查詢用戶
dao 實現
@Override
public User?selectOne(long?id) {
User u =?null;
try {
InputStream in =?Resources.getResourceAsStream("mybatis-config.xml");?SqlSessionFactory fac =?new?SqlSessionFactoryBuilder().build(in);?SqlSession session =?fac.openSession();
u =?session.selectOne("cn.UserMapper.selectOne",
id);
session.close();
} catch?(Exception e) {
e.printStackTrace();
}
return u;
}
mapper 中的?SQL
<select id="selectOne"?resultType="cn.domain.User"> select * from user where id = #{id}
</select>
和?DML 不一樣的地方,查詢操作需要指定把查詢的結果集數據封裝成什么類型的對象,resultType 屬性就是這個作用
思考: resultType 可以不配置嗎? 不可以,需要告訴?MyBatis 把一行數據封裝成什么類型的對象
目前: 需要模型的屬性和表的列需要一一匹配,如果不匹配,無法獲取到數據.
查詢所有用戶
dao 實現
@Override
public List<User>?selectList() {
List<User>?users =?null;
try {
InputStream in =?Resources.getResourceAsStream("mybatis-config.xml");?SqlSessionFactory fac =?new?SqlSessionFactoryBuilder().build(in);?SqlSession session =?fac.openSession();?users =
session.selectList("cn.UserMapper.selectAll");
session.close();
} catch?(Exception e) { e.printStackTrace();
}
return users;
}
mapper 中的?SQL
<select id="selectAll"?resultType="cn.domain.User"> select * from user
</select>
6_細節處理
類型別名
在查詢操作中, 我們需要使用result屬性指定數據封裝的類型, 這里的值類型的全限定名, 每次都編寫的話比較麻煩,為了簡化這里的配置,我們可以在主配置文件(mybatis-config.xml)中對指定的類型做別名的配置
<!-- 為指定包中的類來生成別名,默認是類的簡單名稱?-->
<typeAliases>
<package name="cn.domain"/> </typeAliases>
如此,我們在查詢的SQL中, 使用類的全限定名和使用別名是等價的修改前:
<select id="selectAll"?resultType="cn.User"> select * from user
</select>
修改后:
<select id="selectAll"?resultType="User">
select * from user
</select>
日志管理
在持久層的開發過程中,我們程序員需要隨時觀察SQL的執行情況,如果sql有問題,我們能夠及時發現所以,如果能夠在控制臺中將我們執行的SQL全部打印出來,那么就可以方便的觀察SQL的相關問題
配置日志文件監控MyBatis的運行.
- 將日志相關的jar包添加到項目中
???????
2. 在resources(source folder)中創建配置文件, log4j.properties ,添加下面的內容(直接拷貝)
- Global logging configuration log4j.rootLogger=ERROR, stdout
- 配置要打印日志的包 log4j.loggr..mybatis=TRACE
- Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender?log4j.appender.stdout.layout=org.apache.log4j.PatternLayout?log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
將配置中的 包路徑修改為項目中對應的路徑,我們這里可以使用: cn.mybatis
到此,我們每執行一條?SQL, 都會在控制臺中打印出來,這非常有助于我們對?SQL 的分析,特別是?SQL 不正確的時候
7_抽取?MyBatisUtil 工具類
和?JDBC 中的連接池使用一樣,在整個項目中,我們只需要一個SqlSessionFactory對象,而不需要每次都創建一個新的,
所以,我們將SqlSessionFactory的創建和SqlSession對象的獲取都抽取到工具類中: MyBatisUtil
注意:
加載配置文件沒有填寫:
8_抽取db.properties
在主配置文件中配置的內容較多, 其中包括我們修改頻率較高的數據庫連接信息(driver/url/username/password)等,我們可以在修改這些信息的過程中誤改或者誤刪到其他的配置,為了解決這個問題,我們仍然是將這些信息配置到db.propertie配置文件中,然后再合并到主配置文件即可,如下:
db.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/javaweb
username=root
password=admin
mybatis-cofnig.xml
<configuration>
<!-- 關聯db.properties:為了把連接數據庫的信息單獨放到一個配置文件?--> <properties resource="db.properties"?/>
<!-- 為指定包中的類來生成別名?-->
<typeAliases>
<package name="cn.domain"/> </typeAliases>
<!-- 連接數據庫的環境
default:指定使用哪一個環境的配置
-->
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--
使用${key}取出db.properties中配置的信息
key和db.properties文件中的可以一直即可
-->
<property name="driver"?value="${driverClassName}"/> <property name="url"?value="${url}"/>
<property name="username"?value="${username}"/> <property name="password"?value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 關聯映射文件?-->
<mappers>
<mapper resource="cn\mapper\ProductMapper.xml"/> </mappers>
</configuration>