摘要:將語句硬編碼到代碼中,修改語句需要重新編譯代碼設(shè)想使用配置文件配置。從結(jié)果集中遍歷數(shù)據(jù)的時(shí)候存在硬編碼。表示一個(gè)拼接符號,會(huì)引用注入,所以不建議使用。和表示查詢出一條記錄進(jìn)行映射。
MyBatis是什么
mybatis是托管在github上的ORM框架,讓程序員將主要精力放在SQL上,通過mybatis提供映射方式,自由靈活(SQL的可定制性較高,半自動(dòng)化)生成滿足需求的SQL語句。mybatis可以將向 preparedStatement中的輸入?yún)?shù)自動(dòng)進(jìn)行輸入映射,將查詢結(jié)果集靈活映射成java對象。(輸出映射)
在進(jìn)行項(xiàng)目的編碼之前首先初始化數(shù)據(jù)庫,項(xiàng)目所需要的sql腳本。
原生jdbc中的問題總結(jié)觀察以下的代碼:
@Test public void testJDBC(){ final String DB_DRIVER = "org.gjt.mm.mysql.Driver"; final String DB_URL = "jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf-8"; final String DB_USER = "root"; final String DB_PASSWORD = "mysqladmin"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { Class.forName(DB_DRIVER); conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); String sql = "SELECT * FROM user WHERE username = ?"; pstmt = conn.prepareStatement(sql); pstmt.setString(1, "王五"); rs = pstmt.executeQuery(); while (rs.next()) { System.out.println("id:" + rs.getInt("id") + ",username:" + rs.getString("username")); } } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } finally { if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if( pstmt != null){ try { pstmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
以上的程序中存在以下的問題:
數(shù)據(jù)庫使用時(shí)打開連接,不使用的時(shí)候立即釋放連接。對數(shù)據(jù)庫進(jìn)行了頻繁的打開和關(guān)閉,影響性能(設(shè)想:可以使用DBPool)。
將SQL語句硬編碼到j(luò)ava代碼中,修改SQL語句需要重新編譯java代碼(設(shè)想:使用配置文件配置SQL)。
在向PreparedStatement中設(shè)置參數(shù)的時(shí)候參數(shù)的位置和參數(shù)值硬編碼在代碼中(設(shè)想:配置文件)。
從結(jié)果集中遍歷數(shù)據(jù)的時(shí)候存在硬編碼。(設(shè)想:把結(jié)果集映射成javabean)
MyBatis原理SqlMapConfig.xml:MyBatis全局配置文件(數(shù)據(jù)源、事務(wù)等mybatis運(yùn)行環(huán)境),不是固定名稱;
mapper.xml:映射關(guān)系(配置SQL語句);
SqlSessionFactory:創(chuàng)建會(huì)話(SqlSession);
SqlSession:操作DB(CRUD),面向用戶的接口;
Excutor:執(zhí)行器(SqlSession內(nèi)部通過執(zhí)行器操作DB),接口(有2個(gè)實(shí)現(xiàn)類,基本執(zhí)行器和緩存執(zhí)行器);
mappedstatement:底層封裝對象(sql語句、輸入?yún)?shù)、結(jié)果類型)。
入門程序需求:
根據(jù)id(主鍵)查詢用戶信息
根據(jù)用戶名模糊查詢用戶信息
添加用戶
更新用戶
刪除用戶
在新建一個(gè)源代碼目錄config,在config目錄下使用以下的log4j屬性文件(可以從mybatis示例程序中拷貝):
編碼前的準(zhǔn)備 log4j# 開發(fā)環(huán)境中日志的級別使用DEBUG,生產(chǎn)環(huán)境中日志級別為ERROR ### 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工程目錄如下所示
在SqlMapConfig.xml中配置MyBatis的運(yùn)行環(huán)境:
根據(jù)id查詢用戶信息
1.新建一個(gè)pojo名稱為User,其字段如下:
private int id; private String username; private String sex; private Date birthday; private String address;
2.在映射文件(User.xml,這是原始的ibatis映射方式,如果采用mapper代理則名稱應(yīng)該是UserMapper.xml)中配置sql語句。
在config/sqlmap目錄下新建一個(gè)User.xml(輸入的參數(shù)類型和輸出的結(jié)果集映射的javabean)內(nèi)容如下:
3.在SqlMapConfig.xml中加載User.xml.(在User.xml的configuration中加入以下內(nèi)容)
4.編寫測試類:
/** * 根據(jù)id查詢用戶信息 */ @Test public void testFindUserById() throws IOException{ // mybatis配置 String resource = "SqlMapConfig.xml"; // 得到配置文件的流 InputStream is = Resources.getResourceAsStream(resource); // 創(chuàng)建會(huì)話工廠(傳入配置信息) SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is); // 通過會(huì)話工廠得到Sqlsession SqlSession session = sqlSessionFactory.openSession(); // 查詢 // 參數(shù)一:命名空間下的SQL的id; // 參數(shù)二:和映射文件中匹配的parameterType參數(shù) // 返回值:映射文件中resultType配置的javabean User user = session.selectOne("test.findUserById", 1); System.out.println(user); // 釋放資源(關(guān)閉會(huì)話) session.close(); }根據(jù)用戶信息模糊查詢用戶信息
在User.xml中配置如下:
測試類:
/** * 模糊查詢(可能返回多條) */ @Test public void testFindUserByName() throws IOException { // 通過會(huì)話工廠得到Sqlsession SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession(); // 返回多條記錄 List users = session.selectList("test.findUserByName", "%明%"); System.out.println(users); session.close(); }
在執(zhí)行模糊查詢的時(shí)候我們在編碼的時(shí)候傳入了%作為參數(shù),為了避免出錯(cuò)(少加了%)我們可以在User中配置以下的SQL(同樣:我們需要注意:拼接SQL語句可能導(dǎo)致SQL注入):
在測試代碼中我們可以這樣:
List users = session.selectList("test.findUserByName", "明");
因?yàn)?{value}進(jìn)行SQL拼接可能導(dǎo)致sql注入因此不建議使用。
添加用戶在User.xml中配置Statement如下:
INSERT INTO user(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address});
測試類:
/** * 添加用戶 */ @Test public void testInsertUser() throws IOException{ // 得到sqlsession SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession(); // 實(shí)例化javabean User user = new User(); user.setUsername("蕭晚晴"); user.setBirthday(new Date()); user.setSex("2"); user.setAddress("峨眉山"); // 執(zhí)行插入語句,并提交事務(wù) session.insert("test.insertUser",user); session.commit(); // 關(guān)閉sqlsession session.close(); }自增主鍵的返回
MySQL自增主鍵,執(zhí)行insert提交之前自動(dòng)生成一個(gè)自增主鍵,通過其LAST_INSERT_ID()函數(shù)可以獲得其插入后的自增主鍵。修改以上的插入用戶的statement:
SELECT LAST_INSERT_ID(); INSERT INTO user(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address});
這樣我們就可以在執(zhí)行插入之后取得剛剛插入的記錄的主鍵:
/** * 添加用戶 */ @Test public void testInsertUser() throws IOException{ // 得到sqlsession SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession(); // 實(shí)例化javabean User user = new User(); user.setUsername("蕭晚晴"); user.setBirthday(new Date()); user.setSex("2"); user.setAddress("峨眉山"); // 執(zhí)行插入語句,并提交事務(wù) session.insert("test.insertUser",user); session.commit(); System.out.println(user.getId()); // 得到插入數(shù)據(jù)的主鍵 // 關(guān)閉sqlsession session.close(); }非自增主鍵的返回
可以使用MySQL的uuid()函數(shù)來生成主鍵,需要修改表的id字段為String,長度設(shè)置為35位。執(zhí)行思路是先通過uuid()查詢到主鍵,將主鍵輸入到SQL中。注意:執(zhí)行的uuid()函數(shù)的順序相對于INSERT語句之前執(zhí)行。
SELECT UUID(); INSERT INTO user(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address});
如果使用的是Oracle,序列就類似于MySQL的uuid()函數(shù),替換即可:
刪除用戶SELECT 序列名.nextval(); INSERT INTO user(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address});
映射文件:
DELETE FROM user WHERE id = #{id}
測試類:
/** * 根據(jù)id刪除用戶 */ @Test public void testDeleteUser() throws IOException{ // 得到sqlsession SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession(); // 執(zhí)行刪除語句,并提交事務(wù) session.delete("test.deleteUser", 31); session.commit(); // 關(guān)閉sqlsession session.close(); }更新用戶信息
映射文件
UPDATE user SET username = #{username},birthday=#{birthday},sex=#{sex},address=#{address} WHERE id = #{id}
測試程序
/** * 更新用戶 */ @Test public void testupdateUser() throws IOException{ // 得到sqlsession SqlSession session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("SqlMapConfig.xml")).openSession(); // 實(shí)例化javabean User user = new User(); user.setId(32); user.setUsername("上官飛燕"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("青城山"); // 執(zhí)行更新語句,并提交事務(wù) session.update("test.updateUser",user); session.commit(); // 關(guān)閉sqlsession session.close(); }總結(jié)
parameterType
在映射文件中通過parameterType指定輸入?yún)?shù)的類型。
resultType
在映射文件中通過resultType指定輸出結(jié)果的類型。
#{}和${}
#{}表示一個(gè)占位符號,#{}接收輸入?yún)?shù),類型可以是簡單類型,pojo、hashmap。如果接收簡單類型,#{}中可以寫成value或其它名稱。
#{}接收pojo對象值,通過OGNL讀取對象中的屬性值,通過屬性.屬性.屬性...的方式獲取對象屬性值。${}表示一個(gè)拼接符號,會(huì)引用sql注入,所以不建議使用${}。
${}接收輸入?yún)?shù),類型可以是簡單類型,pojo、hashmap。如果接收簡單類型,${}中只能寫成value。
${}接收pojo對象值,通過OGNL讀取對象中的屬性值,通過屬性.屬性.屬性...的方式獲取對象屬性值。
selectOne和selectList
selectOne表示查詢出一條記錄進(jìn)行映射。如果使用selectOne可以實(shí)現(xiàn)使用selectList也可以實(shí)現(xiàn)(list中只有一個(gè)對象)。
selectList表示查詢出一個(gè)列表(多條記錄)進(jìn)行映射。如果使用selectList查詢多條記錄,不能使用selectOne。
如果使用selectOne報(bào)錯(cuò):
org.apache.ibatis.exceptions.TooManyResultsException: Expected one
result (or null) to be returned by selectOne(), but found: 4
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/64552.html
摘要:前兩篇已經(jīng)構(gòu)建了標(biāo)準(zhǔn)工程實(shí)例,也整合了實(shí)現(xiàn)了簡單數(shù)據(jù)庫訪問,本篇主要更深入的學(xué)習(xí)下,實(shí)現(xiàn)較為完整的數(shù)據(jù)庫的標(biāo)準(zhǔn)服務(wù)。到這里,最復(fù)雜的數(shù)據(jù)訪問基本就算編寫完了。 前兩篇已經(jīng)構(gòu)建了RESTful API標(biāo)準(zhǔn)工程實(shí)例,也整合了MyBatis實(shí)現(xiàn)了簡單數(shù)據(jù)庫訪問,本篇主要更深入的學(xué)習(xí)下,實(shí)現(xiàn)較為完整的數(shù)據(jù)庫CRUD的標(biāo)準(zhǔn)服務(wù)。 首先看下要實(shí)現(xiàn)的效果吧,完成下面截圖部分的API,除了CRUD之外...
摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號作者架構(gòu)師奮斗者掃描主頁左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...
摘要:是最流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一,在應(yīng)用方面,是最好的,關(guān)系數(shù)據(jù)庫管理系統(tǒng)應(yīng)用軟件。是一種關(guān)系數(shù)據(jù)庫管理系統(tǒng),關(guān)系數(shù)據(jù)庫將數(shù)據(jù)保存在不同的表中,而不是將所有數(shù)據(jù)放在一個(gè)大倉庫內(nèi),這樣就增加了速度并提高了靈活性。 本章主要是對MyBatis-Plus的初步介紹,包括一些背景知識(shí)、環(huán)境搭建、初步使用等知識(shí)和例子。對于背景知識(shí),主要包含對MyBatis-Plus的特性介紹、為什么使用MyB...
摘要:代碼自動(dòng)生成底層服務(wù)有很多通用的,利用代碼生成最好不過了,這里作者將代碼生成放在中的,避免與正式代碼沖突。主要通過來實(shí)現(xiàn),項(xiàng)目中的模板文件可以自行定義。相互學(xué)習(xí),共同進(jìn)步 從零開始學(xué)習(xí)Spring Boot也有幾天時(shí)間了,項(xiàng)目已經(jīng)不允許我這么慢慢學(xué)習(xí)了,急需底層變現(xiàn)實(shí)現(xiàn)一套簡單的Restful API用于業(yè)務(wù)支撐。 于是在GitHub上找到了一個(gè)不錯(cuò)的demo,直接看demo搭建自己的...
閱讀 462·2023-04-25 23:00
閱讀 3493·2021-11-22 13:54
閱讀 1892·2021-10-27 14:14
閱讀 1485·2019-08-30 13:59
閱讀 3510·2019-08-23 16:15
閱讀 1957·2019-08-23 16:06
閱讀 3326·2019-08-23 15:26
閱讀 1256·2019-08-23 13:48