TgDao是一款基於Mybatis的編譯期SQL生成器,利用註解來表達SQL,能根據你的方法簽名生成對應的Mapper.xml文件。
它能減小你平常開發中大量簡單SQL的編寫,因爲它只是生成Mapper.xml文件,所以對於複雜的查詢場景,
你一樣能夠本身編寫來完成一些工具所沒法生成的SQL。java
@Table(name = "T_User") public class User { @Id("id") private int id; private String username; private int age; }
上面的model定義了模型和數據庫表的關係,看到下面這些方法的簽名,聰明的你確定能猜出每一個方法的sql吧,這就是這個庫要作的工做。git
@DaoGen(model = User.class) public interface UserDao { @Select @OrderBy("id desc") List<User> queryUser(@Condition(criterion = Criterions.EQUAL, column = "username") String name, @Condition(criterion = Criterions.GREATER, attach = Attach.OR) int age, @Limit int limit, @OffSet int offset); @Select List<User> queryUser2(@Condition(criterion = Criterions.GREATER, column = "age") int min, @Condition(criterion = Criterions.LESS, column = "age") int max); @Select List<User> queryUser3(@Condition(criterion = Criterions.EQUAL, column = "username") String name, @Condition(attach = Attach.OR, column = "id", criterion = Criterions.IN) String[] ids); @Insert(useGeneratedKeys = true, keyProperty = "id") int insert(User user); @BatchInsert(columns = "username,age") int batchInsert(List<User> users); @Update @ModelConditions({ @ModelCondition(field = "id") }) int update(User user); @Delete int delete(@Condition(criterion = Criterions.GREATER, column = "age") int min, @Condition(criterion = Criterions.LESS, column = "age") int max); }
項目地址 https://github.com/twogoods/TgDaogithub
引入以下依賴:sql
<dependency> <groupId>com.github.twogoods</groupId> <artifactId>tgdao-core</artifactId> <version>0.1.3</version> </dependency>
@Table
記錄數據表的名字@Id
記錄主鍵信息@Column
映射了表字段和屬性的關係,若是表字段和類屬性同名,那麼能夠省略這個註解@Ingore
忽略這個類屬性,沒有哪一個表字段與它關聯數據庫
@Table(name = "T_User") public class User { @Id("id") private int id; private String username; private String password; private int age; @Column("old_address") private String oldAddress; @Column("now_address") private String nowAddress; private int state; @Column("created_at") private Timestamp createdAt; @Column("updated_at") private Timestamp updatedAt; @Ignore private String remrk;
@Select @OrderBy("id desc") List<User> queryUser(@Condition(criterion = Criterions.EQUAL, column = "username") String name, @Condition(criterion = Criterions.GREATER, attach = Attach.OR) int age, @Condition(column = "id", criterion = Criterions.IN) String[] ids, @Limit int limit, @OffSet int offset);
columns
:默認 select *
能夠配置columns("username,age")
選擇部分字段;SqlMode
:有兩個選擇,SqlMode.SELECTIVE 和 SqlMode.COMMON,區別是selective會檢查查詢條件的字段是否爲null來實現動態的查詢,即<if test="name != null">username = #{name}</if>
apache
criterion
:查詢條件,=
,<
,>
,in
等,具體見Criterions
column
:與表字段的對應,若與字段名相同可不配置attach
:鏈接 and
,or
, 默認是and
test
:selective下的判斷表達式,即<if test="username != null">
裏的test屬性@Limit
,@OffSet
爲分頁字段。
方法的參數不加任何註解同樣會被當作查詢條件,以下面兩個函數效果是同樣的:數組
@Select() List<User> queryUser(Integer age); @Select() List<User> queryUser(@Condition(criterion = Criterions.EQUAL, column = "age") Integer age);
上面的例子在查詢條件比較多時方法參數會比較多,咱們能夠把查詢條件封裝到一個類裏,使用@ModelConditions
來註解查詢條件,注意被@ModelConditions
只能有一個參數。mybatis
@Select @Page @ModelConditions({ @ModelCondition(field = "username", criterion = Criterions.EQUAL), @ModelCondition(field = "minAge", column = "age", criterion = Criterions.GREATER), @ModelCondition(field = "maxAge", column = "age", criterion = Criterions.LESS), @ModelCondition(field = "ids", column = "id", criterion = Criterions.IN), @ModelCondition(field = "idArr", column = "id", criterion = Criterions.IN, paramType = InType.ARRAY) }) List<User> queryUser5(UserSearch userSearch);
field
:必填,查詢條件中類對應的屬性column
:對應的表字段paramType
:in 查詢下才須要配置,數組爲array
,List爲collection
類型test
:selective下的判斷表達式,即<if test="username != null">
裏的test屬性@Page
只能用在ModelConditions下的查詢,而且方法參數的那個類應該有offset
,limit
這兩個屬性。app
注:框架
@Select(columns = "username,age") List<User> queryUser(Integer age); @Select(columns = "username,age") List<User> queryUser2param(Integer age, String username); <select id="queryUser" resultMap="XXX">select username,age from T_User <where> <if test="age != null">AND age = #{age}</if> </where> </select> <select id="queryUser2param" resultMap="XXX">select username,age from T_User <where> <if test="age != null">AND age = #{age}</if> <if test="username != null">AND username = #{username}</if> </where> </select>
兩個函數生成的sql如上,@Select
的屬性SqlMode
默認是Selective
,因此兩個都有<if>條件判斷,可是這裏第一個函數的sql,
Mybatis不支持,執行會報錯,相似no age getter in java.lang.Interger
,Mybatis會把這惟一的一個參數當作對象來取裏面的值。
解決方法:函數簽名裏強加@Param()
註解,或者@Select
裏使用sqlMode = SqlMode.COMMON
去掉生成sql裏的if判斷。
這個問題只會在方法只有一個參數的狀況下發生,第二個函數生成的sql是ok的。
查詢參數裏@Limit
,@OffSet
或查詢model裏@Page
的分頁功能都比較原始,TgDao只是一款SQL生成器而已,所以你可使用各類插件,
或者與其餘框架集成。對於分頁,能夠無縫與PageHelper整合。
@Select List<User> queryUser2(@Condition(criterion = Criterions.GREATER, column = "age") int min, @Condition(criterion = Criterions.LESS, column = "age") int max); @Test public void testQueryUser2() throws Exception { PageHelper.offsetPage(1, 10); List<User> users = mapper.queryUser2(12, 30); PageInfo page = new PageInfo<>(users); System.out.println(page.getTotal()); Assert.assertTrue(page.getList().size() > 0); }
@Insert(useGeneratedKeys = true, keyProperty = "id")//獲取自增id int insert(User user); @BatchInsert(columns = "username,age")//插入的列 int batchInsert(List<User> users);
BatchInsert
強烈建議寫columns,由於生成的語句並不會過濾null字段,數據庫中插入null易報錯。
@Update(columns = "username,age")//選擇更新某幾個列 @ModelConditions({ @ModelCondition(field = "id") }) int update(User user);
@Delete int delete(@Condition(criterion = Criterions.GREATER, column = "age") int min, @Condition(criterion = Criterions.LESS, column = "age") int max); @Delete @ModelConditions({ @ModelCondition(attach = Attach.AND, field = "minAge", column = "age", criterion = Criterions.GREATER), @ModelCondition(attach = Attach.AND, field = "maxAge", column = "age", criterion = Criterions.LESS) }) int delete2(UserSearch userSearch);
@Select
,@Count
,@Update
,@Delete
都有selective
這個屬性,這個屬性有兩個值,分別是SqlMode.COMMON
和SqlMode.SELECTIVE
。
它們的區別在下面這段生成的xml裏顯示的很清楚,SqlMode.SELECTIVE
引入了Mybatis的動態SQL能力。
<!-- SELECTIVE --> <select id="queryUser" resultMap="BaseResultMap">select username,age from T_User <where> <if test="name!=null and name!=''">AND username = #{name}</if> <if test="age != null">OR age = #{age}</if> </where> </select> <!-- COMMON --> <select id="queryUser" resultMap="BaseResultMap">select username,age from T_User <where> AND username = #{name} OR age = #{age} </where> </select>
@Select
,@Count
默認的selective屬性是SqlMode.SELECTIVE
,這樣查詢語句能夠充分利用Mybatis的動態SQL能力。
而@Update
,@Delete
默認是SqlMode.COMMON
,這樣作的緣由是:selective模式下若是參數全是null
會使得where語句裏沒有任何條件,
最終變成全表的更新和刪除,這是一個極其危險的動做。因此@Update
,@Delete
慎用SqlMode.SELECTIVE
模式。
在介紹這個註解時要先介紹一下Mybatis本身的@Param
註解,@Param
註解在方法的參數上,給參數定義了一個名字,
這樣能夠在xml的sql裏使用這個名字來取得參數所對應的值。以下:
List<User> queryUser(@Param("name") String name); <select id="queryUser">select * from T_User where username=#{name} </select>
明明參數就叫name,爲何還要@Param
註解一個名字name呢?這是由於Java編譯完,會丟掉參數名,以致於運行期mybatis不知道這個參數叫什麼,因此須要註解一個名字。
在運行時看到mybatis報錯如:Parameter 'XXX' not found. Available parameters are...
這就是沒有這個註解致使的問題。
可是在Java8裏咱們已經能夠經過給javac 添加-parameters
參數來保留參數名字信息,這樣mybatis會利用這個信息,這樣就不須要加@Param
註解了。
maven能夠經過以下方式設置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin>
然而有一種狀況-parameters
也無能爲力,List<User> queryUser4(List ids);
當參數是collection或者數組類型時,mybatis依舊沒法認出ids
這個參數,只認collection
和array
。
而@Params
註解是Mybatis自身註解@Param
和-parameters
外的另一種解決方案。@Params
能夠註解在類和方法上,
被它註解的類和方法會在編譯期自動給全部方法參數加上@Param
註解,它借鑑了lombok的方式在編譯期修改抽象語法樹從而改變編譯生成的字節碼文件。
@Select(columns = "username,age") @Params List<User> queryUser(Integer age, String username); //編譯後 List<User> queryUser(@Param("age") Integer var1, @Param("username") String var2);
更多請看example
若是你只修改了其中一個的代碼,那麼另外一個未修改的代碼編譯器就不作處理,這樣這一次編譯就沒法獲得所有的信息,因此TgDao沒法生成最新版本的xml。
解決方法是每次mvn clean compile
先清除一下編譯目錄,更好的方案正在尋找...