您好,登錄后才能下訂單哦!
本篇內容介紹了“@InsertProvider執行的原理是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
其中包含入參,與數據庫表字段的映射字段。
在執行Provider類里面的動態插入sql的時候,程序會調用 AbstractSQL這個抽象類,執行里面的兩個拼接字符串的方法
public T INSERT_INTO(String tableName) { this.sql().statementType = AbstractSQL.SQLStatement.StatementType.INSERT; this.sql().tables.add(tableName); return this.getSelf(); } public T VALUES(String columns, String values) { this.sql().columns.add(columns); this.sql().values.add(values); return this.getSelf(); }
這個抽象class里面有一個私有的靜態類SQLStatement和私有靜態SalfAppendable類。
SQLStatement類里面有一個共有靜態枚舉類,里面有它的一個私有構造函數,枚舉被設計成是單例模式,即枚舉類型會由JVM在加載的時候,實例化枚舉對象,你在枚舉類中定義了多少個就會實例化多少個,JVM為了保證每一個枚舉類元素的唯一實例,是不會允許外部進行new的,所以會把構造函數設計成private,防止用戶生成實例,破壞唯一性。
枚舉類里面含有增刪查改四種。私有的靜態類SQLStatement有sql語句的各種關鍵字list,distinct是boolean類型,例如:
List<String> sets = new ArrayList();
子類ArrayList實例化List,因為List是一個接口,所以只能依靠其“子類”(在這里是List的實現類)來進行實例化,這里的對象是List的對象。
private void sqlClause(AbstractSQL.SafeAppendable builder, String keyword, List<String> parts, String open, String close, String conjunction) { if(!parts.isEmpty()) { if(!builder.isEmpty()) { builder.append("\n"); } builder.append(keyword); builder.append(" "); builder.append(open); String last = "________"; int i = 0; for(int n = parts.size(); i < n; ++i) { String part = (String)parts.get(i); if(i > 0 && !part.equals(") \nAND (") && !part.equals(") \nOR (") && !last.equals(") \nAND (") && !last.equals(") \nOR (")) { builder.append(conjunction); } builder.append(part); last = part; } builder.append(close); } }
上面這個函數就是增刪查改通用的sql解析函數。
下面是增調用的函數
private String insertSQL(AbstractSQL.SafeAppendable builder) { this.sqlClause(builder, "INSERT INTO", this.tables, "", "", ""); this.sqlClause(builder, "", this.columns, "(", ")", ", "); this.sqlClause(builder, "VALUES", this.values, "(", ")", ", "); return builder.toString(); }
通過下面的函數確定增刪查改對應調用的函數
public String sql(Appendable a) { AbstractSQL.SafeAppendable builder = new AbstractSQL.SafeAppendable(a); if(this.statementType == null) { return null; } else { String answer; switch(null.$SwitchMap$org$apache$ibatis$jdbc$AbstractSQL$SQLStatement$StatementType[this.statementType.ordinal()]) { case 1: answer = this.deleteSQL(builder); break; case 2: answer = this.insertSQL(builder); break; case 3: answer = this.selectSQL(builder); break; case 4: answer = this.updateSQL(builder); break; default: answer = null; } return answer; } }
私有靜態SalfAppendable類是進行sql字符串的拼接。
里面有是一個私有不可以改變的Appendable對象。
private static class SafeAppendable { private final Appendable a; private boolean empty = true; public SafeAppendable(Appendable a) { this.a = a; } public AbstractSQL.SafeAppendable append(CharSequence s) { try { if(this.empty && s.length() > 0) { this.empty = false; } this.a.append(s); return this; } catch (IOException var3) { throw new RuntimeException(var3); } } public boolean isEmpty() { return this.empty; } }
然后調用ProviderSqlSource類,接著調用不可變類MappedStatement類,再調用BaseStatementHandler類,--->PreparedStatementHandler等。
代表從注解中讀取相關的映射語句的內容,它創建的sql會被傳到數據庫。
根據SQL語句的類型不同,mybatis提供了多種SqlSource的具體實現:
1)StaticSqlSource
:最終靜態SQL語句的封裝,其他類型的SqlSource最終都委托給StaticSqlSource。
2)RawSqlSource
:原始靜態SQL語句的封裝,在加載時就已經確定了SQL語句,沒有、等動態標簽和${} SQL拼接,比動態SQL語句要快,因為不需要運行時解析SQL節點。
3)DynamicSqlSource
:動態SQL語句的封裝,在運行時需要根據參數處理、等標簽或者${} SQL拼接之后才能生成最后要執行的靜態SQL語句。
4)ProviderSqlSource
:當SQL語句通過指定的類和方法獲取時(使用@XXXProvider注解),需要使用本類,它會通過反射調用相應的方法得到SQL語句
@Insert和@InsertProvider都是用來在實體類的Mapper類里注解保存方法的SQL語句。
不同的是,@Insert是直接配置SQL語句,而@InsertProvider則是通過SQL工廠類及對應的方法生產SQL語句,這種方法的好處在于,我們可以根據不同的需求生產出不同的SQL,適用性更好。
(1)項目中的實體類
(2)每個實體類對應的Mapper方法
(3)SQL工廠
Blog實體類屬性:
為了方便說明,屬性不設置過多,假設Blog類的屬性有blogId,title,author
(1)@Insert的注解方式
@Insert("insert into blog(blogId,title,author) values(#blogId,#title,#author)") public boolean saveBlog(Blog blog);
說明:由于我們不能確定哪些屬性沒有值,那只能把所有屬性都寫上了。
(2)@InsertProvider的注解方式
@InsertProvider(type = SqlFactory.class,method = "insertBlog") public boolean saveBlog(@Param("bean")Blog blog);
說明:type指明SQL工廠類,method是工廠類里對應的方法
SqlFactory類代碼:
public class SqlFactory { public String insertBlog(Map<String,Object> para){ Blog blog = (Blog)para.get("bean"); // SQL sql = new SQL(); //SQL語句對象,所在包:org.apache.ibatis.jdbc.SQL sql.INSERT_INTO("blog"); if(blog.getBlogId() != null){ //判斷blogId屬性是否有值 sql.VALUES("blogId", blog.getBlogId()); } if(blog.getTitle() != null){//判斷title屬性是否有值 sql.VALUES("title", blog.getTitle()); } if(blog.getAuthor() != null){//判斷author屬性是否有值 sql.VALUES("author", blog.getAuthor()); } return sql.toString(); } }
使用@InsertProvider的方式,可以根據實體中有值的屬性,進行動態的生成插入SQL語句如:
blogId和title有值:insert into blog(blogId,title) values(v1,v2);
author和title有值:insert into blog(author,title) values(v1,v2);
總結:其實也就是說因為mybaits的xml中有<if test=""></if>標簽來動態生成sql,但是在程序代碼中沒有辦法這么做。
那么insertprovider就是充當了這樣一個角色,來動態的生成sql。
與之類似的還有MyBatis注解的巧妙使用---@InsertProvider,@UpdateProvider,@DeleteProvider和@SelectProvider等等。
“@InsertProvider執行的原理是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。