MyBatis學習筆記(一)
標簽: java web框架
MyBatis概述
MyBatis本是Apache的一個開源項目iBatis, 2010年這個項目由apache software foundation遷移到了google code,并且改名為MyBatis。2013年11月遷移到Github。
MyBatis 是一個優秀的持久層框架,它對jdbc的操作數據庫的過程進行封裝,使開發者只需要關注 SQL 本身,而不需要花費精力去處理例如注冊驅動、 創建connection、創建 statement、手動設置參數、結果集檢索等 jdbc繁雜的過程代碼。
Mybatis 通過 xml 或注解的方式將要執行的各種 statement(statement、 preparedStatemnt、CallableStatement)配置起來,并通過 java 對象和 statement 中的 sql 進行映射生成最終執行的sql語句,最后由mybatis框架執行sql并將結果映射成java對象并返回。
使用JDBC存在的問題
JDBC的編程步驟
- 加載數據庫驅動
- 創建獲取數據庫連接
- 創建Statement對象
- 執行SQL語句并返回ResultSet結果集
- 處理結果集
- 釋放資源
存在的問題
- 數據庫連接創建、釋放頻繁造成系統資源浪費,從而影響系統性能。如果使用數據庫連接池可解決此問題。
- SQL語句在代碼中硬編碼,造成代碼不易維護,實際應用中SQL變化的可能較大,SQL語句變動需要改變 java代碼。
- 使用preparedStatement向占位符傳參數存在硬編碼,因為sql語句的where條件不一定,可能多也可能少,修改sql還要修改代碼,系統不易維護。
- 對結果集解析存在硬編碼(查詢列名),sql變化導致解析代碼變化,系統不易維護,如果能將數據庫記錄封裝成pojo對象解析比較方便。
MyBatis架構
MyBatis架構圖
架構圖解釋
MyBatis配置文件
-
SqlMapConfig.xml
MyBatis的全局配置文件,配置了MyBatis的運行環境等信息
-
SqlSessionFactory
會話工廠,用于創建SqlSession,通過MyBatis環境等配置信息構造SqlSessionFactory
-
SqlSession
會話,操作數據庫主要通過SqlSession進行
-
Executor
MyBatis底層自定義了Executor執行器接口操作數據庫,Executor接口有兩個實現,一個是基本執行器、一個是緩存執行器
-
MappedStatement
Mapped Statement也是mybatis一個底層封裝對象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個sql對應一個Mapped Statement對象,sql的id即是Mapped statement的id。
-
輸入映射
Mapped Statement對sql執行輸入參數進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行sql前將輸入的java對象映射至sql中,輸入參數映射就是jdbc編程中對preparedStatement設置參數
-
輸出映射
Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執行sql后將輸出結果映射至java對象中,輸出結果映射過程相當于jdbc編程中對結果的解析處理過程
-
Mybatis入門程序
MyBatis下載
點擊上述鏈接進入頁面后,再點擊下圖中的位置即可下載;下載完畢后壓縮包中有MyBatis的依賴包(在lib目錄下)。
環境配置
-
導入MyBatis依賴包以及數據庫連接驅動
-
編寫SqlMapConfig.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> <!-- 與spring整合以后,environments配置將被廢除 --> <environments default="development"> <environment id="development"> <!--事務管理,使用jdbc--> <transactionManager type="jdbc"></transactionManager> <!--數據庫連接池--> <dataSource type="POOLED"> <!--配置數據庫連接信息--> <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/mybatistest?characterEncoding=UTF-8"></property> <property name="username" value="數據庫用戶名"></property> <property name="password" value="數據庫密碼"></property> </dataSource> </environment> </environments> </configuration>
-
編寫日志輸出文件log4j.properties,日志輸出文件的編寫如下:
# Global logging configuration log4j.rootLogger=DEBUG, stdout # 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
-
在數據庫中創建表,我創建的是user表:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(32) NOT NULL COMMENT '用戶名稱', `birthday` date DEFAULT NULL COMMENT '生日', `sex` char(1) DEFAULT NULL COMMENT '性別', `address` varchar(256) DEFAULT NULL COMMENT '地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
-
編寫數據庫中表的對應的pojo(Plain Ordinary Java Object,其實就是Java Bean)
-
編寫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"> <!-- namespace:命名空間,用于隔離SQL -> <mapper namespace="com.xurenyi.pojo.User"> <!-- id:sql的id parameterType:輸入參數的類型 resultType:輸出結果的類型,應該填寫對應POJO的全路徑 #{v}:占位符,相當于jdbc中的? --> <select id="findUserById" parameterType="Integer" resultType="com.xurenyi.pojo.User"> select * from user where id=#{v} </select> </mapper>
-
在SqlMapperConfig.xml中配置UserMapper文件,寫法如下:
<!--配置UserMapper.xml文件的位置--> <mappers> <mapper resource="config/UserMapper.xml"></mapper> </mappers>
案例
根據id查詢單個用戶
- 在UserMapper.xml中編寫SQL語句:
<!-- mapper:用于編寫SQL語句,mapper元素中可以寫多個SQL語句 namespace:命名空間,用于隔離SQL --> <mapper namespace="com.xurenyi.pojo.User"> <!-- id:SQL語句的id parameterType:輸入參數的類型 resultType:輸出結果的類型,應該填寫對應POJO的全路徑 '#{v}':占位符,相當于jdbc中的? --> <!-- 根據id查詢單個用戶 --> <select id="findUserById" parameterType="Integer" resultType="com.xurenyi.pojo.User"> select * from user where id=${value} </select> </mapper>
- 編寫測試方法:
//根據id查找單個用戶 @Test public void findUserById() throws IOException { //加載SqlMapConfig.xml配置文件,把配置文件的路徑作為參數傳入 InputStream in = Resources.getResourceAsStream("config/SqlMapConfig.xml"); //創建SqlSessionFactoryBuilder SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); //獲取SqlSessionFactory(根據配置文件創建SqlSessionFactory) SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(in); //獲取SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); //執行select操作,傳入參數是SQL語句的id、SQL語句中的查找參數 User user = sqlSession.selectOne("findUserById", 1); System.out.println(user); }
注意: 由于下面的例子中測試代碼的前面部分與根據id查詢單個用戶
中的測試代碼是一樣的,所以在下述的例子中,就只寫SQL語句(寫在<mapper></mapper>
元素中)以及通過sqlSession
進行操作數據庫的語句(例如根據id查詢單個用戶
測試代碼中的User user = sqlSession.selectOne("findUserById", 1);
這句),省略獲取SqlSession對象的代碼。
根據用戶名模糊查詢用戶
- 方式一
- SQL語句
<!--模糊查詢--> <select id="findUserListByLike" parameterType="String" resultType="com.xurenyi.pojo.User"> select * from user where username like #{v} </select>
- 測試代碼
/* 獲取SqlSession對象的代碼,略 */ List<User> userList = sqlSession.selectList("findUserListByLike", "%張%");
- SQL語句
- 方式二
- SQL語句
<!--模糊查詢--> <select id="findUserListByLike" parameterType="String" resultType="com.xurenyi.pojo.User"> select * from user where username like '%${value}%' </select>
- 測試代碼
/* 獲取SqlSession對象的代碼,略 */ List<User> userList = sqlSession.selectList("findUserListByLike", "張");
- SQL語句
- 方式三
- SQL語句
<!--模糊查詢--> <select id="findUserListByLike" parameterType="String" resultType="com.xurenyi.pojo.User"> select * from user where username like "%"#{v}"%" </select>
- 測試代碼
/* 獲取SqlSession對象的代碼,略 */ List<User> userList = sqlSession.selectList("findUserListByLike", "張");
- SQL語句
添加用戶
- SQL語句
<!--添加用戶 參數類型是User對象,所以在SQL語句中取參數值的時候,需要把User實體類里面的屬性名寫進去,而不能在'#{}'里面隨便寫幾個字母 --> <insert id="addUser" parameterType="com.xurenyi.pojo.User"> <!--取參數的時候需要把User里面的屬性寫進'#{}',而不能隨便寫--> insert into user values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
- 測試代碼
/* 獲取SqlSession對象的代碼,略 */ User user = new User(); user.setId(null); user.setUsername("用戶名"); user.setBirthday(new Date()); user.setSex("男"); user.setAddress("用戶地址"); // 需要"改變"數據庫中數據的操作(例如:插入、刪除、修改數據)都有一個int類型的返回值,該返回值表示對數據庫中記錄影響的行數 int addUser = sqlSession.insert("addUser", user); sqlSession.commit(); //需要自己提交事務(在增刪改查這四個操作中,除了查詢操作,其余三個操作都需要提交事務)
添加用戶返回ID
- 需求:在使用MyBatis插入一個用戶數據以后,獲取該用戶的id。
- select LAST_INSERT_ID();
- 這是MySQL中提供的查詢最新添加數據的id,但是執行該條語句時,需要先執行一條插入語句才能返回id,否則就返回0。
- SQL語句
<insert id="addUser" parameterType="com.xurenyi.pojo.User"> <!-- 標簽實現主鍵返回 keyColumn:主鍵對應數據庫表中的哪一列 keyProperty:主鍵對應pojo中的哪一個屬性 order:設置在執行insert語句之前執行查詢id的操作,還是在執行insert語句之后執行查詢id的操作 --> <selectKey keyColumn="id" keyProperty="id" resultType="Integer" order="AFTER"> select LAST_INSERT_ID() </selectKey> <!--取參數的時候需要把User里面的屬性寫進#{},而不能隨便寫--> insert into user values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
- 測試代碼
/* 獲取SqlSession對象的代碼,略 */ User user = new User(); user.setId(null); user.setUsername("用戶名"); user.setBirthday(new Date()); user.setSex("男"); user.setAddress("用戶地址"); // 需要"改變"數據庫中數據的操作(例如:插入、刪除、修改數據)都有一個int類型的返回值,該返回值表示對數據庫中記錄影響的行數 int addUser = sqlSession.insert("addUser", user); sqlSession.commit(); //需要自己提交事務(在增刪改查這四個操作中,除了查詢操作,其余三個操作都需要提交事務) System.out.println(user.getId()); //在提交事務之后獲取id并打印
根據id修改用戶數據
- SQL語句
<!--根據id修改用戶數據--> <update id="updateUserById" parameterType="com.xurenyi.pojo.User"> update user set address=#{address},birthday=#{birthday} where id=#{id} </update>
- 測試代碼
/* 獲取SqlSession對象的代碼,略 */ User user = new User(); user.setId(28); user.setAddress("修改后的地址"); user.setUsername("修改后的姓名"); user.setSex("女"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Date date = simpleDateFormat.parse("1994-01-01 17:06:00"); user.setBirthday(date); sqlSession.update("updateUserById", user); //提交事務 sqlSession.commit(); //關閉sqlSession sqlSession.close();
根據id刪除用戶
- SQL語句
<!--根據id刪除用戶數據--> <delete id="deleteUserById" parameterType="Integer"> delete from user where id=#{id} </delete>
- 測試代碼
/* 獲取SqlSession對象的代碼,略 */ int count=sqlSession.delete("deleteUserById",28); //提交事務 sqlSession.commit(); System.out.println(count); //關閉sqlSession sqlSession.close();
小結
- #{}和${}的區別
- #{}
#{}表示一個占位符號,通過#{}可以實現preparedStatement向占位符中設置值,自動進行java類型和jdbc類型轉換。#{}可以有效防止sql注入。 #{}可以接收簡單類型值或pojo屬性值。 如果parameterType傳輸單個簡單類型值, #{}括號中可以是 value 或其它名稱。 - $ {}
$ {}表示拼接 sql 串,通過$ {}可以將parameterType傳入的內容拼接在sql中且不進行 jdbc類型轉換,$ {}可以接收簡單類型值或 pojo 屬性值,如果 parameterType 傳輸單個簡單類型值,${}括號中只能是 value。
- #{}
- parameterType和resultType
- parameterType
指定輸入參數類型,mybatis通過ognl從輸入對象中獲取參數值拼接在 sql 中。 - resultType
指定輸出結果類型,mybatis 將 sql 查詢結果的一行記錄數據映射為resultType 指定類型的對象。如果有多條數據,則分別進行映射,并把對象放到容器 List 中。
- parameterType
- selectOne和selectList
- selectOne
selectOne用于查詢一條記錄,如果使用selectOne查詢多條記錄會報錯。 - selectList
selectList用于查詢一條或多條記錄。
- selectOne
- MyBatis解決JDBC編程的問題
-
問題1
- 描述:數據庫連接創建、釋放頻繁造成系統資源浪費從而影響系統性能,如果使用數據庫連接池可解決此問題
- 解決:在 SqlMapConfig.xml 中配置數據連接池,使用連接池管理數據庫鏈接
-
問題2
- 描述:Sql 語句寫在代碼中造成代碼不易維護,實際應用 sql 變化的可能較大,sql 變動需要改變 java代碼
- 解決:將 Sql 語句配置在 XXXXmapper.xml 文件中與 java 代碼分離
-
問題3
- 描述:向sql語句傳參數麻煩,因為sql語句的where條件不一定,可能多也可能少,占位符需要和參數一一對應
- 解決:Mybatis 自動將 java 對象映射至 sql 語句,通過 statement 中的 parameterType 定義輸入參數的類型
-
問題4
- 描述:對結果集解析麻煩,sql變化導致解析代碼變化,且解析前需要遍歷,如果 能將數據庫記錄封裝成pojo對象解析比較方便
- 解決:Mybatis自動將sql執行結果映射至java對象,通過statement中的 resultType定義輸出結果的類型
-
- MyBatis和Hibernate的異同
- Mybatis和hibernate不同,它不完全是一個ORM框架,因為MyBatis需要程序員自己編寫Sql語句。mybatis可以通過XML或注解方式靈活配置要運行的sql語句,并將java對象和sql語句映射生成最終執行的sql,最后將sql執行的結果再映射生成java對象。
- Mybatis學習門檻低,簡單易學,程序員直接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,非常適合對關系數據模型要求不高的軟件開發,例如:互聯網軟件、企業運營類軟件等,因為這類軟件需求變化頻繁,一旦需求變化要求成果輸出迅速。但是靈活的前提是 mybatis 無法做到數據庫無關性,如果需要實現支持多種數據庫的軟件則需要自定義多套 sql 映射文件,工作量大。
- Hibernate 對象/關系映射能力強,數據庫無關性好,對于關系模型要求高的軟件(例如需求固定的定制化軟件)如果用hibernate開發可以節省很多代碼,提高效率。但是Hibernate的學習門檻高,要精通門檻更高,而且怎么設計O/R映射,在性能和對象模型之間如何權衡,以及怎樣用好Hibernate需要具有很強的經驗和能力才行。
- 總之,按照用戶的需求在有限的資源環境下只要能做出維護性、擴展性良好的軟件架構都是好架構,所以框架只有適合才是最好。
SqlMapConfig.xml配置文件詳解
SqlMapConfig.xml中配置的內容和順序
這里選講幾個元素。
-
properties(屬性)
-
properties是用來加載外部配置文件的,其寫法如下:
<!--使用resource加載外部配置文件--> <properties resource="外部配置文件的路徑"> <!--如果外部配置文件中有該屬性,那么內部定義的屬性被外部屬性覆蓋--> <property name="" value=""/> </properties>
-
MyBatis加載屬性的順序
先讀取properties元素體內自定義的屬性,再讀取properties中resource指定路徑的外部配置文件中的屬性,如果在外部配置文件中有同名屬性,則后者會覆蓋前者。
-
-
typeAliases(類型別名)
有時候寫實體類的全路徑比較麻煩,所以可以取一個別名,這樣可以在Mapper.xml中直接寫別名調用。
-
定義單個別名
定義單個別名的配置寫法如下:
<typeAliases> <!--定義單個別名 type:需要被取別名的對象全路徑 alias:對應的別名 --> <typeAlias type="com.xurenyi.pojo.User" alias="user"></typeAlias> </typeAliases>
-
批量定義別名
批量定義別名的配置寫法如下:
<typeAliases> <!--批量定義別名 會掃描整個包下的類,別名是類名(大小寫不敏感) --> <package name="com.xurenyi.pojo"></package>
-
-
mappers(映射器)
-
用法1
<mapper resource="mapper.xml配置文件的全路徑"></mapper>
-
用法2
<mapper class="對應的mapper類的路徑"></mapper>
此種方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中。
-
用法3
<package name="包路徑"></mapper>
此種方法要求mapper接口名稱和mapper映射文件名稱相同,且放在同一個目錄中。
實際項目開發中,會使用這種方法。
-
智能推薦
Mybatis學習筆記(一)
1、環境描述 java版本:1.8 開發工具:idea 2018版 mysql:8.x版本 mybatis:3.4.6版本 lombok mybatis 在開發中最為關鍵的是其 SqlSession 的使用和 mapper 文件的配置。 本文將圍繞它來介紹Mybatis的入門案例。 2、項目結構 2.1 配置文件 在 idea 中,使用maven項目。在 resources 資源文件夾中創建文件夾...
MyBatis學習筆記(一)
一、MyBatis介紹 MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記...
Mybatis學習筆記一
Mybatis學習筆記一 概述 Mybatis 是一個優秀的基于 java 的持久層框架,它內部封裝了 jdbc,使開發者只需要關注 sql 語句本身,而不需要花費精力去處理加載驅動、創建連接、創建 statement 等繁雜的過程。 mybatis 通過 xml 或注解的方式將要執行的各種 statement 配置起來,并通過 java 對象和 statement 中sql 的動態參數進行映射生...
MyBatis學習筆記(一)
1 、對原生態jdbc程序中問題總結 jdbc編程步驟: 1、 加載數據庫驅動 2、 創建并獲取數據庫鏈接 3、 創建jdbc statement對象 4、 設置sql語句 5、 設置sql語句中的參數(使用preparedStatement) 6、 通過statement執行sql并獲取結果 7、 對sql執行結...
Mybatis學習筆記(一)
嗷嗷 環境統一 JDK1.8 Mysql5.7 maven3.6.1 簡介 什么是mybatis MyBatis 本是apache的一個開源項目iBatis, 2010年這個項目由apache software foundation 遷移到了google code,并且改名為MyBatis 。2013年11月遷移到Github。 iBATIS一詞來源于“internet”和...
猜你喜歡
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...