Mybatis JPA 插件簡介


前段時間了解到Spring JPA,感覺挺好用,但其依賴於Hibernate,本人看到Hibernate就頭大(不是說Hibernate不好哈,而是進階太難),於是做了一個迷你版的Mybatis JPA.

代碼地址(github): https://github.com/svili365/mybatis-jpa

代碼地址(gitee): https://gitee.com/svili/mybatis-jpa

QQ交流群:246912326

因為版本更新,可能會導致博客與代碼不對應,強烈建議閱讀代碼倉庫的wiki文檔

maven

<dependency>
            <groupId>com.littlenb</groupId>
            <artifactId>mybatis-jpa</artifactId>
            <version>2.1.1</version>
 </dependency>

1.1 版本說明

v2.0.1:純凈版的resultTypePlugin

v2.1.0:在v2.0.1基礎上,增加SQL構建,InsertDefinition|UpdateDifinition

v2.1.1:增加自定義枚舉值,ICodeEnum,@CodeEnum,IntCodeEnumTypeHandler,StringCodeEnumTypeHandler

1.2 工作模式

1.)mybatis-jpa 是基於Mybatis的增強插件,沒有對依賴包(源代碼)造成污染.

2.)ResultTypePlugin在運行時攔截,每個被攔截的方法會在初次調用時完成解析.

3.)mybatis-jpa SQL的解析和Statement的注冊時機,是在Spring applicationContext初始化完成時,只會解析一次.

4.)由mybatis-jpa 解析的Mapper接口中定義的方法(method),將被注冊到Mybatis Configuration中,即Mapper的代理和注入由依舊由Mybatis和Spring構建和管理,不影響原有的代碼模式和工作模式.

1.3 約定

1.)Entity實體類需使用@Entity或@Table注解標記,類中字段類型不允許使用基本數據類型(如:使用Integer定義整形而不是int);

2.)ResultTypePlugin支持結果集的嵌套,SQL的構建(InsertDefinition|UpdateDifinition)會忽略實體類的嵌套.

3.)按照Mybatis約定,Enum枚舉類型默認以 enum.name() 解析,若要解析為enum.ordinal(),需使用注解@Enumrated(value = EnumType.ORDINAL)標識.

4.)使用自定義枚舉值,枚舉類型需實現ICodeEnum接口,並使用注解@CodeEnum標記Field.@CodeEnum優先級高於@Enumrated.

 

插件清單

  • ResultTypePlugin 

  • DefinitionStatementScanner 

2.1 ResultTypePlugin

對於常規的結果映射,不需要再構建ResultMap,ResultTypePlugin增加了Mybatis對結果映射(JavaBean/POJO)中JPA注解的處理。

映射規則:

  • 名稱匹配默認為駝峰(Java Field)與下划線(SQL Column)

  • 使用@Column注解中name屬性指定SQL Column

  • 使用@Transient注解標記非持久化字段(不需要結果集映射的字段)

類型處理:

  • Boolean-->BooleanTypeHandler

  • Enum默認為EnumTypeHandler

    使用@Enumerated(EnumType.ORDINAL) 指定為 EnumOrdinalTypeHandler

  • Enum實現ICodeEnum接口實現自定義枚舉值

    使用@CodeEnum(CodeType.INT) 指定為 IntCodeEnumTypeHandler

    或@CodeEnum(CodeType.STRING) 指定為 StringCodeEnumTypeHandler

    @CodeEnum 優先級 高於 @Enumerated

結果集嵌套:

  • 支持OneToOne
  • 支持OneToMany

e.g.

mybatis.xml

<configuration>
    <plugins>
        <plugin interceptor="com.mybatis.jpa.plugin.ResultTypePlugin">
        </plugin>
    </plugins>
</configuration>

 

JavaBean

@Entity
public class UserArchive {// <resultMap id="xxx" type="userArchive">

    @Id
    private Long userId;// <id property="id" column="user_id" />
                           
    /** 默認駝峰與下划線轉換 */
    private String userName;// <result property="username" column="user_name"/>

    /** 枚舉類型 */
    @Enumerated(EnumType.ORDINAL)
    private SexEnum sex;// <result property="sex" column="sex" typeHandler=EnumOrdinalTypeHandler/>
    
    /** 枚舉類型,自定義值 */
    @CodeEnum(CodeType.INT)
    private PoliticalEnum political;// <result property="political" column="political" typeHandler=IntCodeEnumTypeHandler/>
    
    /** 屬性名與列名不一致 */
    @Column(name = "gmt_create")
    private Date createTime;// <result property="createTime" column="gmt_create"/>
}// </resultMap>

 

mapper.xml

<!-- in xml,declare the resultType -->
<select id="selectById" resultType="userArchive">
    SELECT * FROM t_sys_user_archive WHERE user_id = #{userId}
</select>

 

DefinitionStatementScanner

注冊MappedStatement,基於注解,僅支持Insert和Update。

@InsertDefinition:

  • selective: 默認值false(處理null屬性)

@UpdateDefinition:

  • selective: 默認值false(處理null屬性)

  • where: SQL condition

e.g.

Spring 容器初始化完成后執行

@Service
public class DefinitionStatementInit {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @PostConstruct
    public void init() {
        Configuration configuration = sqlSessionFactory.getConfiguration();
        StatementBuildable statementBuildable = new DefinitionStatementBuilder(configuration);
        DefinitionStatementScanner.Builder builder = new DefinitionStatementScanner.Builder();
        DefinitionStatementScanner definitionStatementScanner = builder.configuration(configuration).basePackages(new String[]{"com.mybatis.jpa.mapper"})
                .statementBuilder(statementBuildable).build();
        definitionStatementScanner.scan();
    }
}

 

Mapper

@Mapper
@Repository
public interface UserUpdateMapper {

    @InsertDefinition(selective = true)
    int insert(User user);

    @UpdateDefinition(selective = true, where = " user_id = #{userId}")
    int updateById(User user);
}

 

更多示例請查看test目錄代碼。

 

如果你想深入了解,項目代碼目錄還算清晰,源碼中有大量必要的注釋,你會發現有部分英文注釋,不要慌,是我寫的,現在感覺有些代碼用英文描述反而會簡單一些,用中文反而不能夠被很好的理解.

代碼的構建思路及代碼解析,見博文:http://www.cnblogs.com/svili/p/7232323.html

因個人能力有限,如有不足之處,請多包涵,歡迎交流/指正.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM