简介
在之前的文章里讨论过mybatis纯xml或者annotation的开发。同时,也讨论了针对不同对象关系情况下的实现细节。在实际的开发应用中,我们会发现,有时候单纯的使用某一种方式来开发的话并不一定有最佳的效率。比如说当我们使用纯xml的时候,会发现里面有很多比较繁琐的配置,而且因为很多sql语句因为是写在xml配置文件里,一个是容易出错,另外对于一些特殊符号还要做一些处理,这样就显得开发的效率不理想。但是使用annotation的话,如果想要重用一些元素比如ResultMap的话就会比较麻烦,每次要重复定义一些元素。所以,如果能够结合两者一些比较好的地方,对于开发来说会更加理想。
示例
SQL脚本
示例对应的SQL脚本如下:
CREATE TABLE ADDRESSES ( ADDR_ID INT(11) NOT NULL AUTO_INCREMENT, STREET VARCHAR(50) NOT NULL, CITY VARCHAR(50) NOT NULL, STATE VARCHAR(50) NOT NULL, ZIP VARCHAR(10) DEFAULT NULL, COUNTRY VARCHAR(50) NOT NULL, PRIMARY KEY (ADDR_ID) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=LATIN1; CREATE TABLE STUDENTS ( STUD_ID INT(11) NOT NULL AUTO_INCREMENT, NAME VARCHAR(50) NOT NULL, EMAIL VARCHAR(50) NOT NULL, PHONE VARCHAR(15) DEFAULT NULL, DOB DATE DEFAULT NULL, GENDER VARCHAR(6) DEFAULT NULL, BIO LONGTEXT DEFAULT NULL, PIC BLOB DEFAULT NULL, ADDR_ID INT(11) DEFAULT NULL, PRIMARY KEY (STUD_ID), UNIQUE KEY UK_EMAIL (EMAIL), CONSTRAINT FK_STUDENTS_ADDR FOREIGN KEY (ADDR_ID) REFERENCES ADDRESSES (ADDR_ID) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=LATIN1; CREATE TABLE TUTORS ( TUTOR_ID INT(11) NOT NULL AUTO_INCREMENT, NAME VARCHAR(50) NOT NULL, EMAIL VARCHAR(50) NOT NULL, PHONE VARCHAR(15) DEFAULT NULL, DOB DATE DEFAULT NULL, GENDER VARCHAR(6) DEFAULT NULL, BIO LONGTEXT DEFAULT NULL, PIC BLOB DEFAULT NULL, ADDR_ID INT(11) DEFAULT NULL, PRIMARY KEY (TUTOR_ID), UNIQUE KEY UK_EMAIL (EMAIL), CONSTRAINT FK_TUTORS_ADDR FOREIGN KEY (ADDR_ID) REFERENCES ADDRESSES (ADDR_ID) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=LATIN1; CREATE TABLE COURSES ( COURSE_ID INT(11) NOT NULL AUTO_INCREMENT, NAME VARCHAR(100) NOT NULL, DESCRIPTION VARCHAR(512) DEFAULT NULL, START_DATE DATE DEFAULT NULL, END_DATE DATE DEFAULT NULL, TUTOR_ID INT(11) NOT NULL, PRIMARY KEY (COURSE_ID), CONSTRAINT FK_COURSE_TUTOR FOREIGN KEY (TUTOR_ID) REFERENCES TUTORS (TUTOR_ID) ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=LATIN1; CREATE TABLE COURSE_ENROLLMENT ( COURSE_ID INT(11) NOT NULL, STUD_ID INT(11) NOT NULL, PRIMARY KEY (COURSE_ID,STUD_ID), CONSTRAINT FK_ENROLLMENT_STUD FOREIGN KEY (STUD_ID) REFERENCES STUDENTS (STUD_ID), CONSTRAINT FK_ENROLLMENT_COURSE FOREIGN KEY (COURSE_ID) REFERENCES COURSES (COURSE_ID) ) ENGINE=INNODB DEFAULT CHARSET=LATIN1;
mybatis配置文件
对应的mybatis配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="application.properties"/> <typeAliases> <package name="com.yunzero.domain"/> </typeAliases> <typeHandlers> <typeHandler handler="com.yunzero.typehandlers.PhoneTypeHandler"/> </typeHandlers> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <mappers> <package name="com.yunzero.mappers"/> </mappers> </configuration>
这个文件主要指定数据源和配置环境,另外也指定类型转换和对应的mapper接口。
mapper接口和对应配置文件
我们这里重点考察TutorMapper,它的对应的配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.yunzero.mappers.TutorMapper"> <resultMap type="Course" id="CourseResult"> <id column="course_id" property="courseId"/> <result column="course_name" property="name"/> <result column="description" property="description"/> <result column="start_date" property="startDate"/> <result column="end_date" property="endDate"/> </resultMap> <resultMap type="Tutor" id="TutorResult"> <id column="tutor_id" property="tutorId"/> <result column="tutor_name" property="name"/> <result column="email" property="email"/> <result column="phone" property="phone"/> <association property="address" resultMap="com.yunzero.mappers.AddressMapper.AddressResult"/> <collection property="courses" resultMap="CourseResult"></collection> </resultMap> </mapper>
这里定义了两个映射的结果,一个是CourseResult,一个就是TutorResult。这里也引用了其他地方定义的ResultMap。
对应的TutorMapper接口定义如下:
public interface TutorMapper { @SelectProvider(type=TutorDynaSqlProvider.class, method="findAllTutorsSql") List<Tutor> findAllTutors(); @SelectProvider(type=TutorDynaSqlProvider.class, method="findTutorByIdSql") Tutor findTutorById(int tutorId); @SelectProvider(type=TutorDynaSqlProvider.class, method="findTutorByNameAndEmailSql") Tutor findTutorByNameAndEmail(@Param("name")String name, @Param("email")String email); @InsertProvider(type=TutorDynaSqlProvider.class, method="insertTutor") @Options(useGeneratedKeys=true, keyProperty="tutorId") int insertTutor(Tutor tutor); @UpdateProvider(type=TutorDynaSqlProvider.class, method="updateTutor") int updateTutor(Tutor tutor); @DeleteProvider(type=TutorDynaSqlProvider.class, method="deleteTutor") int deleteTutor(int tutorId); @SelectProvider(type=TutorDynaSqlProvider.class, method="selectTutorById") @ResultMap("com.yunzero.mappers.TutorMapper.TutorResult") Tutor selectTutorById(int tutorId); }
这里有几个值得注意的地方。和前面简单的定义@Select, @Insert等方法不同,这里我们不是直接在这里写sql脚本。因为一方面除了前面提到的在字符串形式写的sql更加容易出错以外,在某些地方,我们需要结合程序逻辑和一些参数做一些更加复杂的运算。也就是动态sql。这些问题使得直接在xml或者annotation里写sql并不是一个很理想的选择。于是mybatis提供了一种比较好的写sql的方法,叫sqlprovider。它使得写sql脚本的代码显得更加面向对象,也显得好理解一点。
SQL provider
前面示例里使用到的sql provider类详细实现如下:
public class TutorDynaSqlProvider { public String findAllTutorsSql() { return new SQL() {{ SELECT("tutor_id as tutorId, name, email"); FROM("tutors"); }}.toString(); } public String findTutorByIdSql(final int tutorId) { return new SQL() {{ SELECT("tutor_id as tutorId, name, email"); FROM("TUTORS"); WHERE("tutor_id = #{tutorId}"); // using placeholder #{tutorId} }}.toString(); } public String findTutorByNameAndEmailSql(Map<String, Object> map) { return new SQL() {{ SELECT("tutor_id as tutorId, name, email"); FROM("tutors"); WHERE("name=#{name} AND email=#{email}"); }}.toString(); } public String insertTutor(final Tutor tutor) { return new SQL() {{ INSERT_INTO("TUTORS"); if (tutor.getName() != null) { VALUES("NAME", "#{name}"); } if (tutor.getEmail() != null) { VALUES("EMAIL", "#{email}"); } }}.toString(); } public String updateTutor(final Tutor tutor) { return new SQL() {{ UPDATE("TUTORS"); if (tutor.getName() != null) { SET("NAME = #{name}"); } if (tutor.getEmail() != null) { SET("EMAIL = #{email}"); } WHERE("TUTOR_ID = #{tutorId}"); }}.toString(); } public String deleteTutor(int tutorId) { return new SQL() {{ DELETE_FROM("TUTORS"); WHERE("TUTOR_ID = #{tutorId}"); }}.toString(); } public String selectTutorById() { return new SQL() {{ SELECT("t.tutor_id, t.name as tutor_name, email"); SELECT("a.addr_id, street, city, state, zip, country"); SELECT("course_id, c.name as course_name, description, start_date, end_date"); FROM("TUTORS t"); LEFT_OUTER_JOIN("ADDRESSES a on t.addr_id=a.addr_id"); LEFT_OUTER_JOIN("COURSES c on t.tutor_id=c.tutor_id"); WHERE("t.TUTOR_ID = #{id}"); }}.toString(); } }
通过这部分的实现我们可以看到,我们可以将sql脚本,每个操作对应一个方法。然后在annotation里指定对应的类和方法。针对每个不同的实现,我们来看一下它们的细节。
SelectProvider
SelectProvider里有几种情况,针对没有参数和有参数的情况。在没有参数的情况下,比如findAllTutorsSql,这里只需要在Mapper接口里指定对应的sqlprovider类和方法。在有一个参数的时候,比如有这个方法:
@SelectProvider(type=TutorDynaSqlProvider.class, method="findTutorByIdSql") Tutor findTutorById(int tutorId);
在这里mapper 接口的方法里其实是提供了一个参数的。但是sqlprovider方法里的实现如下:
public String findTutorByIdSql() { return new SQL() {{ SELECT("tutor_id as tutorId, name, email"); FROM("TUTORS"); WHERE("tutor_id = #{tutorId}"); // using placeholder #{tutorId} }}.toString(); }
这里不是简单的做一个sql的拼接,注意到这里将mapper接口里的参数和占位符里的参数一一对应上了。当然,这里的findTutorByIdSql方法并没有带参数。
如果需要provider方法里的方法支持mapper接口里多个参数的话,需要做一些调整。比如mapper接口里有方法:
@SelectProvider(type=TutorDynaSqlProvider.class, method="findTutorByNameAndEmailSql") Tutor findTutorByNameAndEmail(@Param("name")String name, @Param("email")String email);
这里接口指定了两个@Param参数,它就对应sqlprovider提供的参数里需要映射过来的字段。而在这种情况下,sqlProvider对应的方法必须提供一个Map<String, Object>类型的参数。它对应的方法实现如下:
public String findTutorByNameAndEmailSql(Map<String, Object> map) { return new SQL() {{ SELECT("tutor_id as tutorId, name, email"); FROM("TUTORS"); WHERE("name=#{name} AND email=#{email}"); }}.toString(); }
除了selectprovider,其他的像insertProvider, deleteProvider, updateProvider则相对比较简单直观。它们有一个共同的特点就是所有的sqlprovider方法都必须返回String类型的值。另外,我们也注意到,有的方法里有一些判断的逻辑,比如
public String updateTutor(final Tutor tutor) { return new SQL() {{ UPDATE("TUTORS"); if (tutor.getName() != null) { SET("NAME = #{name}"); } if (tutor.getEmail() != null) { SET("EMAIL = #{email}"); } WHERE("TUTOR_ID = #{tutorId}"); }}.toString(); }
这种判断方式如果用纯sql的方式来实现会显得比较麻烦。但是这里用一种类似sql并结合java程序逻辑的方式实现了。它比对应的xml配置方式显得更加灵活。
总结
总的来说,结合xml, annotaion和sqlprovider的时候,需要注意几个点。一个是mapper的xml配置适合定义一些ResultMap,这样可以方便它们被其他的mapper接口重用。另外,annotation里适合指定对应的sqlprovider以及对应resultMap引用。而对于具体sql语句的编写,在sqlprovider里写则比较合适。而且,要特别注意sqlprovider里方法的参数和mapper接口里方法参数的对应。在这一块,目前感觉还不是很灵活。
相关推荐
NULL 博文链接:https://shmilyaw-hotmail-com.iteye.com/blog/2354678
NULL 博文链接:https://shmilyaw-hotmail-com.iteye.com/blog/2354307
标签:annotation、baomidou、mybatis、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...
NULL 博文链接:https://shmilyaw-hotmail-com.iteye.com/blog/2357862
NULL 博文链接:https://shmilyaw-hotmail-com.iteye.com/blog/2360287
Mybatis编程:基于XML的实现 使用mysql数据库,配置下数据库就可以直接运行 Mybatis编程步骤分为: 步骤1、创建好MySQL数据库 步骤2、在pom.xml中添加mysql-connector-java和Mybatis依赖 步骤3、创建实体类User...
赠送jar包:mybatis-plus-annotation-3.1.0.jar; 赠送原API文档:mybatis-plus-annotation-3.1.0-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.1.0-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...
标签:annotation、baomidou、mybatis、jar包、java、中英对照文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明...
赠送jar包:mybatis-plus-annotation-3.2.0.jar; 赠送原API文档:mybatis-plus-annotation-3.2.0-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.2.0-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...
赠送jar包:mybatis-paginator-1.2.15.jar; 赠送原API文档:mybatis-paginator-1.2.15-javadoc.jar; 赠送源代码:mybatis-paginator-1.2.15-sources.jar; 赠送Maven依赖信息文件:mybatis-paginator-1.2.15.pom;...
赠送jar包:mybatis-plus-annotation-3.1.0.jar; 赠送原API文档:mybatis-plus-annotation-3.1.0-javadoc.jar; 赠送源代码:mybatis-plus-annotation-3.1.0-sources.jar; 赠送Maven依赖信息文件:mybatis-plus-...
mybatis-plus-annotation-3.4.0.jar
Mybatis编程示例:基于注解的实现 使用mysql数据库,配置好数据库后即可直接使用 mybatis基于注解的实现有以下步骤: 步骤1、定义sql映射接口(在src/main/java下创建mapper包) 步骤2、将sql映射接口添加到Mybatis...
mybatis 3.4.5 ,想用自取,mybatis 3.4.5 ,想用自取,mybatis 3.4.5 ,想用自取,mybatis 3.4.5 ,想用自取。
Spring+mybatis annotation形式 进行增删查改,使用maven容器,配置完整,自己运行多次无问题
mybatis-3.2.6(最新mybatis jar).zip
01_eesy_02mybatis_annotation:mybatis学习