摘要:本章主要介紹的是的基礎應用和源碼涉及的相關等,主要包含的內容有的簡介反射動態代理包含代理和代理使用和代碼生成器等。組件生命周期,如圖測試代碼生成器代碼生成器,又稱逆向工程。
本章主要介紹的是MyBatis的基礎應用和源碼涉及的相關等,主要包含的內容有MyBatis的簡介、反射、動態代理(包含JDK代理和cglib代理)、MyBatis使用和代碼生成器等。
1.1 MyBatis簡介MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。
關于MyBatis相關的信息,大家可以參考如下:
MyBatis官網: http://www.mybatis.org/
MyBatis文檔: http://www.mybatis.org/mybati...
MyBatis源碼地址: https://github.com/mybatis/my...
JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱為java語言的反射機制。
JAVA反射(放射)機制:“程序運行時,允許改變程序結構或變量類型,這種語言稱為動態語言”。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。但是JAVA有著一個非常突出的動態相關機制:Reflection,用在Java身上指的是我們可以于運行時加載、探知、使用編譯期間完全未知的classes。換句話說,Java程序可以加載一個運行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),并生成其對象實體、或對其fields設值、或喚起其methods。
從實用的角度看,筆者認為有如下幾個場景?大家可以做一個思考。
(1) 逆向代碼,例如反編譯;
(2) 與注解結合的框架,現在有不少java框架都采用注解的方式,例如Spring既可以通過注解管理事務又可以通過XML方式管理事務;
(3) 插件系統, 程序設計了加載新JAR的功能,陌生JAR文件在程序運行時加入,被編譯成class文件,通過反射機制加載進內存;
(4) 配置文件中的休眠class類, 一個程序有許許多多功能,不可能相對應的class文件一次性全部加載進內存,只能是加載進維持程序運行的基本class,其余功能只有等用的時候,采用觸發機制,通過xml配置文件獲取類名等信息,然后通過反射機制加載相關class進內存。
1.2.3 反射實例代碼如下:
package cn.reflect; import java.lang.reflect.Method; public class ReflectService { /** * 測試方法 * @param name */ public void testReflect(String name) { System.out.println("hello:"+name); } /** * 測試入口 * @throws Exception */ public static void main(String[] args) throws Exception { /** * 通過反射創建ReflectService對象 */ Object service = Class.forName(ReflectService.class.getName()).newInstance(); /** * 獲取服務方法 */ Method method = service.getClass().getMethod("testReflect", String.class); method.invoke(service, "張三"); } }1.2.4反射的優缺點
反射在給我們帶來極大的便利的同時,也帶給我們潛在的危害。這也就是有利也有弊。
反射的優點:
反射提高了程序的靈活性和擴展性,降低耦合性,提高自適應能力。它允許程序創建和控制任何類的對象,無需提前硬編碼目標類。
反射的缺點:
(1)性能問題:使用反射基本上是一種解釋操作,用于字段和方法接入時要遠慢于直接代碼。因此反射機制主要應用在對靈活性和擴展性要求很高的系統框架上,普通程序不建議使用。
(2)使用反射會模糊程序內內部邏輯:程序員希望在源代碼中看到程序的邏輯,反射等繞過了源代碼的技術,因而會帶來維護問題。反射代碼比相應的直接代碼更復雜。
1.3 動態代理 1.3.1 動態代理簡介動態代理有兩種方式,一種是JDK的代理,另外一種是cglib代理。
它們之間的區別是,JDK是代理接口,cglib代理類。
換言之,一個是接口方式,一個是類的方式,類的方式通常表現為繼承。
步驟如下:
(1)編寫接口類
HelloService.java
package cn.reflect; public interface HelloService { public void sayHello(String name); }
(2)編寫實現類
HelloServiceImpl.java
package cn.reflect; public class HelloServiceImpl implements HelloService { public void sayHello(String name) { // TODO Auto-generated method stub System.err.println("hello:"+name); } }
(3)編寫代理類
HelloServiceProxy.java
package cn.reflect; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class HelloServiceProxy implements InvocationHandler { /** * 真實服務對象 */ private Object target; public Object bind(Object target){ this.target=target; /** * 取得代理對象 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);//jdk代理對象需要提供接口 } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("我是JDK動態代理對象"); Object result = null; /** * 反射方法調用前 */ System.out.println("我準備說hello"); /** * 執行方法,相當于調用HelloServiceImpl中的sayHello方法 */ result = method.invoke(target, args); /** * 反射方法后調用 */ System.out.println("我說過hello了"); return result; } }
(4)編寫運行測試類
HelloServiceMain.java
package cn.reflect; public class HelloServiceMain { public static void main(String[] args) { HelloServiceProxy helloHandle = new HelloServiceProxy(); HelloService proxy = (HelloService) helloHandle.bind(new HelloServiceImpl()); proxy.sayHello("張三"); } }1.3.3 cglib代理應用實例
JDK提供的動態代理存在缺陷,必須提供接口才能使用,沒有接口就不能使用,為了克服這個缺陷,我們可以采用cglib代理,它是一種流行的動態代理。
步驟如下:
(1) 導入maven依賴
cglib cglib 3.2.4
(2) 編寫運行測試類
HelloServiceCgLib.java
package cn.reflect; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class HelloServiceCgLib implements MethodInterceptor{ private Object target; /** * 創建代理對象 */ public Object getInstance(Object target) { this.target=target; Enhancer enHancer = new Enhancer(); enHancer.setSuperclass(this.target.getClass()); enHancer.setCallback(this); return enHancer.create(); } public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable { // TODO Auto-generated method stub System.out.println("我是cglib代理對象"); Object returnObj = proxy.invoke(obj, arg); /** * 反射方法前調用 */ System.out.println("我準備說hello"); /** * 反射方法后調用 */ System.out.println("我說過hello了"); return returnObj; } }1.4 MyBatis使用 1.4.1 導入依賴
由于采用的是maven,只需引入maven對應的依賴即可,通常情況下,只要maven依賴導入準確,一般情況下很少會出現因為依賴沖突的問題導致項目運行失敗。
pom.xml
1.4.2 準備SQL腳本4.0.0 cn.youcong.mybatis mybatis 0.0.1-SNAPSHOT org.mybatis mybatis 3.4.6 mysql mysql-connector-java 5.1.38 junit junit 4.12 test
CREATE TABLE `user` ( `user_id` int(8) NOT NULL AUTO_INCREMENT COMMENT "用戶主鍵", `login_code` varchar(20) NOT NULL COMMENT "用戶編碼(登錄賬戶) 手機號 郵箱號", `user_name` varchar(20) NOT NULL COMMENT "用戶名", `password` varchar(40) NOT NULL COMMENT "密碼", `sex` int(2) NOT NULL COMMENT "性別", `identity_card` varchar(20) DEFAULT NULL COMMENT "身份證", `create_time` datetime NOT NULL COMMENT "創建時間", `create_by` varchar(10) NOT NULL COMMENT "創建人", `update_time` datetime NOT NULL COMMENT "更新時間", `update_by` varchar(10) NOT NULL COMMENT "更新人", `status` int(2) NOT NULL DEFAULT "0" COMMENT "狀態:0注冊新用戶 1郵件認證用戶 2管理員 3黑名單", PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;1.4.3 編寫實體
package com.blog.entity; import java.io.Serializable; import java.util.Date; import java.io.Serializable; public class User{ private static final long serialVersionUID = 1L; /** * 用戶主鍵 */ private Integer userId; /** * 用戶編碼(登錄賬戶) 手機號 郵箱號 */ private String loginCode; /** * 用戶名 */ private String userName; /** * 密碼 */ private String password; /** * 性別 */ private Integer sex; /** * 身份證 */ private String identityCard; /** * 創建時間 */ private Date createTime; /** * 創建人 */ private String createBy; /** * 更新時間 */ private Date updateTime; /** * 更新人 */ private String updateBy; /** * 狀態:0注冊新用戶 1郵件認證用戶 2管理員 3黑名單 */ private Integer status; public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } public static long getSerialversionuid() { return serialVersionUID; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getLoginCode() { return loginCode; } public void setLoginCode(String loginCode) { this.loginCode = loginCode; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getSex() { return sex; } public void setSex(Integer sex) { this.sex = sex; } public String getIdentityCard() { return identityCard; } public void setIdentityCard(String identityCard) { this.identityCard = identityCard; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getCreateBy() { return createBy; } public void setCreateBy(String createBy) { this.createBy = createBy; } public String getUpdateBy() { return updateBy; } public void setUpdateBy(String updateBy) { this.updateBy = updateBy; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } }1.4.4 編寫數據訪問層及其對應的XML文件
package com.blog.dao; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import com.blog.entity.User; public interface UserDao { @Select("select * from `user` where user_id=#{userId}") @Results(@Result(property="userName",column="user_name")) User selectOne(int userId); }
@Select是MyBatis的注解寫法,當字段名和屬性名一致時,可以直接@Select不需要@Results,@Results的作用就是因為實體屬性與字段不一致,為了獲取查詢結果,必須要這樣。
當然了你也可以不寫注解,直接在對應的UserDao.xml寫,如果是UserDao.xml里面寫的話,就會變成這樣
package com.blog.dao; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import com.blog.entity.User; public interface UserDao { User selectOne(int userId); }
需要在UserDao.xml中編寫
user_id, login_code, user_name, password, sex, identity_card, create_time, create_by, update_time, update_by, status
除了
user_id, login_code, user_name, password, sex, identity_card, create_time, create_by, update_time, update_by, status
MyBatis常用的兩種寫法,XML方式和注解方式,但是無論你采用哪種,對應的XML文件必須要存在。
其實
前提必須要在mybatis-config.xml配置
但是有人覺得,如果我的類有很多,豈不是要配置很多,太麻煩了,別怕,MyBatis已經為你想到了
這樣配置就解決了重復配置的麻煩
其實除了這樣,如果你想標新立異點,還可以再實體最上面加上@Alias注解
這就是MyBatis的別名三種方式/策略。
1.4.5 編寫mybatis-config.xml配置文件mybatis-config.xml這個配置沒多大用,坦白說。
因為后期與Spring整合由Spring來管理數據庫連接池對象。
不過還是要稍微講講,以讓讀者達到開卷有益的目的或者是讓沒有學過的或者已經學過但是不知道的漲漲見識。
package com.blog.config; import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class SqlSessionFactoryUtils { private static SqlSessionFactory sqlSessionFactory = null; public static SqlSessionFactory getSqlSessionFactory() { InputStream is = null; if(sqlSessionFactory==null) { String resource = "mybatis/mybatis-config.xml"; try { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(resource)); return sqlSessionFactory; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return sqlSessionFactory; } }
說到上述代碼,順便談談MyBatis的核心組件。它的核心組件主要有這么幾個,如下所示:
SqlSessionFactoryBuilder:它會根據配置信息或者代碼來生成SqlSessionFactory;
SqlSessionFactory:依賴工廠生成SqlSession;
SqlSession:是一個即可發送SQL執行返回結果,也可以獲取Mapper接口;
Sql Mapper:它是MyBatis的新設計組件,它是由一個Java接口和XML文件(或注解)構建,需要給出對應的SQL和映射規則。它負責發送SQL去執行并返回結果。
用一張圖來表示它們之間的關系,如圖:
它們的生命周期在此稍微說一下:
(1)SqlSessionFacotoryBuilder
SqlSessionFacotoryBuilder是利用XML和Java代碼獲得資源來構建SqlSessionFactory的,通過它可以構建多個SqlSessionFactory,它的作用就是一個構建器,一旦我們構建了SqlSessionFactory,它的作用就完結,它就失去存在的意義。這時我們應該毫不猶豫的廢棄它,將它回收。所以它的生命周期只存在方法局部,它的作用就是生成SqlSessionFactory。
(2)SqlSessionFactory的作用是創建SqlSession,而SqlSession就是一個會話,相當于JDBC中的Connection對象。每次應用程序需要訪問數據庫,我們就要通過SqlSessionFactory創建SqlSession,所以SqlSessionFactory應該在MyBatis應用的整個生命周期中。而如果我們多次創建同一個數據庫的SqlSessionFactory,則每次創建SqlSessionFactory會打開更多的數據庫連接資源,那么連接資源就很快會被耗盡。因此SqlSessionFactory的責任是唯一的,它的責任就是創建SqlSession,所以我們果斷采用單例模式。如果采用多例,那么它對數據庫連接的消耗是很大的,不利于我們統一管理。所以正確的做法是使得每個數據庫只對應一個SqlSessionFactory,管理好數據庫資源分配,避免過多的Connection被消耗。
(3)SqlSession
SqlSession是一個會話,相當于JDBC的一個Connection對象,它的生命周期應該是在請求數據庫處理事務的過程中。它是一個線程不安全的對象,在涉及多線程的時候我們需要特別當心,操作數據庫需要注意其隔離級別,數據庫鎖等高級特性。此外,每次創建的SqlSession都必須及時關閉它,它長期存在就會使數據庫連接池的活動資源減少,對系統性能的影響很大。
(4)Mapper
Mapper是一個接口,而沒有任何實現類,它的作用是發送SQL,然后返回我們需要的結果,或者執行SQL從而修改數據庫的數據,因此它應該在一個SqlSession事務方法之內,是一個方法級別的東西。它就如同JDBC中的一條SQL語句的執行,它的最大范圍和SqlSession是相同的。盡管我們想一直保存著Mapper,但是你會發現它很難控制,所以盡量在一個SqlSession事務的方法中使用它們,然后廢棄掉。
MyBatis組件生命周期,如圖:
1.4.7 測試package mybatis; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.blog.config.SqlSessionFactoryUtils; import com.blog.dao.UserDao; import com.blog.entity.User; public class MyBatisTest { @Test public void testName() throws Exception { SqlSession sqlSession = null; sqlSession = SqlSessionFactoryUtils.getSqlSessionFactory().openSession(); UserDao userDao = sqlSession.getMapper(UserDao.class); User user = userDao.selectOne(1); System.out.println(user.getUserName()); } }1.5 MyBatis代碼生成器
MyBatis代碼生成器,又稱逆向工程。
關于逆向工程的優點和缺點,我覺得我還是要說說。
逆向工程的優點是:自動化生成實體類和對應的增刪改查,效率相對于之前個人開發時一個個寫增刪改查要高的多
逆向工程的缺點是:xml中的sql語句加入了mybatis自身的動態sql和一大堆判斷等,對于對動態sql不是十分熟練的人而言,以后再功能擴展上會很困難。
================
MyBatis代碼生成器我分為兩個,一個是動態web工程,另一個是現在比較流行的maven工程,本質上都是一樣,只是項目管理jar包的方式不一樣。
(1)導包
(2)新建generator.xml文件,進行配置
(3)測試
import java.io.File; import java.util.ArrayList; import java.util.List; import org.mybatis.generator.api.MyBatisGenerator; import org.mybatis.generator.config.Configuration; import org.mybatis.generator.config.xml.ConfigurationParser; import org.mybatis.generator.internal.DefaultShellCallback; public class GeneratorSqlmap { public void generator() throws Exception{ Listwarnings = new ArrayList (); boolean overwrite = true; //指定 逆向工程配置文件 File configFile = new File("src/generatorConfig.xml"); ConfigurationParser cp = new ConfigurationParser(warnings); Configuration config = cp.parseConfiguration(configFile); DefaultShellCallback callback = new DefaultShellCallback(overwrite); MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings); myBatisGenerator.generate(null); } public static void main(String[] args) throws Exception { try { GeneratorSqlmap generatorSqlmap = new GeneratorSqlmap(); generatorSqlmap.generator(); } catch (Exception e) { e.printStackTrace(); } } }
測試結果在控制臺打印如下,表示成功
1.5.2 maven工程(1)導入maven依賴
4.0.0 cn.mybatis.generator mybatis-generator 0.0.1-SNAPSHOT UTF-8 mysql mysql-connector-java 5.1.35 org.mybatis.generator mybatis-generator-core 1.3.2 org.apache.maven.plugins maven-compiler-plugin 1.8 3.3 org.mybatis.generator mybatis-generator-maven-plugin 1.3.2 mysql mysql-connector-java 5.1.35 src/main/resources/generatorConfig.xml true
(2)在src/main/resource目錄下新建配置文件generatorConfig.xml
(3)右擊進入run as 點擊maven build 如下圖輸入:mybatis-generator:generate
運行結果如下,表示成功
注意:運行成功后,直接是看不到生成的代碼,還需要刷新一下(refresh)。
1.6 小結通過上面的內容,我相信讀者對于MyBatis已經有了大致的了解,通過相關的代碼示例,我相信讀者應該知道怎么使用MyBatis了。當然了,這僅僅只是MyBatis的冰山一角,MyBatis的特性還有很多。不過我之所以講MyBatis也是為了后續讀者更好理解MyBatis-plus。
本文主要參考我個人的博客園中的MyBatis系列相關的,可以說這篇文章是之前MyBatis相關教程不太完善的補充。希望能夠幫助到大家。
最后,如需轉載本文,請附源地址,謝謝合作。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72724.html
摘要:是最流行的關系型數據庫管理系統之一,在應用方面,是最好的,關系數據庫管理系統應用軟件。是一種關系數據庫管理系統,關系數據庫將數據保存在不同的表中,而不是將所有數據放在一個大倉庫內,這樣就增加了速度并提高了靈活性。 本章主要是對MyBatis-Plus的初步介紹,包括一些背景知識、環境搭建、初步使用等知識和例子。對于背景知識,主要包含對MyBatis-Plus的特性介紹、為什么使用MyB...
摘要:跟兩年前寫和配置相關的文件相比,這真是十分的簡單了??梢栽囍鴮懸粋€小小的,有很多視頻教程跟著一步步做就成,我是跟著慕課網上的視頻學習的。對于寫快一年的我來說初學這個還是很欣喜的。 環境配置 Mac 上搭建 java 開發環境http://starzhou.com/blogs/jav... 初始化項目 參考鏈接http://start.spring.io/ 從此鏈接中輸入項目名,并選擇相...
摘要:從使用到原理學習線程池關于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實現在軟件開發中,分散于應用中多出的功能被稱為橫切關注點如事務安全緩存等。 Java 程序媛手把手教你設計模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經風雨慢慢變老,回首走過的點點滴滴,依然清楚的記得當初愛情萌芽的模樣…… Java 進階面試問題列表 -...
摘要:各方面有各種常見的良好示例,包括日志記錄,聲明式事務,安全性,緩存等。聲明式事務管理這意味著你從業務代碼中分離事務管理。但作為一種橫切關注點,聲明式事務管理可以使用方法進行模塊化。支持使用框架的聲明式事務管理。 本章主要內容包括Spring簡介、Spring的兩大特性(IOC和AOP)、事務MyBatis集成Spring等。也許有讀者會疑惑,明明是MyBatis-Plus實戰,怎么還講...
閱讀 2837·2023-04-25 20:02
閱讀 1435·2021-11-11 16:55
閱讀 614·2021-09-26 09:46
閱讀 6203·2021-09-22 15:55
閱讀 1823·2021-08-09 13:41
閱讀 1572·2019-08-30 15:52
閱讀 2371·2019-08-30 14:13
閱讀 3289·2019-08-26 13:48