简介
在之前的文章里讨论过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接口里方法参数的对应。在这一块,目前感觉还不是很灵活。
相关推荐
本篇“mybatis学习总结:annotation示例改进”主要关注的是如何利用MyBatis的注解来优化数据库操作。在现代开发环境中,注解已经成为了简化配置、提高代码可读性的重要工具。以下是关于MyBatis注解使用的一些关键...
在"MyBatis-CRUD-Annotation.zip"这个压缩包中,很显然,它包含了一个关于如何使用MyBatis的注解进行CRUD(创建、读取、更新、删除)操作的示例或教程。以下是对MyBatis中注解使用及相关知识点的详细解释: 1. **...
spring-boot-mybatis-annotation-mulidatasource:springboot+mybatis(注解版)多数据源最简解决方案 spring-boot-thymeleaf:simple spring boot thymeleaf demo spring-boot-jpa-thymeleaf-curd:spring boot + ...
本篇将详细介绍如何将Spring MVC与Mybatis进行整合,并提供相关配置和操作步骤。 **1. Spring MVC 概述** Spring MVC是Spring框架的一部分,它是一个基于模型-视图-控制器(MVC)设计模式的Web应用框架。它负责处理...
SpringBoot和Mybatis是两个非常流行的Java开发框架,SpringBoot简化了Spring的配置,而Mybatis则是一个轻量级的持久层框架,专注于SQL映射和接口操作。本示例源码将展示如何将这两个框架整合在一起,创建一个高效、...
1.Configuration.xml 是 mybatis 用来建立 sessionFactory 用的,里面主要包含了数据库连接相关东西,还有 java 类所对应的别名,比如 <typeAlias alias="User" type="com.yihaomen.mybatis.model.User"/> 这个别名...
MyBatis SQL Mapper XML 配置文件用于映射 SQL 模板语句与 Java 类型的配置。 MyBatis SQL Mapper.Annotation MyBatis SQL Mapper.Annotation 是 Java 注解的方式,用于替代 SQL Mapper XML 配置文件。 MyBatis ...
1. **添加依赖**:在`pom.xml`文件中引入Spring Boot的MyBatis和MyBatis Plus依赖。通常包括`spring-boot-starter-data-jdbc`,`mybatis-spring-boot-starter`以及`mybatis-plus-boot-starter`。 ```xml ...
在提供的"day03_ms"压缩包文件中,可能包含的是关于Spring和MyBatis配置的具体示例代码,如XML配置文件、Mapper接口、映射文件等。通过分析这些文件,可以加深对Spring和MyBatis集成的理解,以及学习如何在实际项目...
在本文中,我们将深入探讨如何在SpringBoot应用中集成并使用MyBatis Plus。MyBatis Plus(简称MP)...通过阅读和理解这个示例,你可以更好地掌握SpringBoot与MyBatis Plus的集成方法,以及如何在项目中有效地使用它们。
spring-boot-mybatis-annotation-mulidatasource:springboot+mybatis(注解版)多数据源最简解决方案 spring-boot-thymeleaf:simple spring boot thymeleaf demo spring-boot-jpa-thymeleaf-curd:spring boot +...
最后,启动Spring Boot应用,通过上述配置,MyBatis Plus将与Spring Boot无缝集成,提供简洁易用的数据操作API,同时实现了数据表的自动更新功能。通过`mybatisPlusDemo`项目中的示例代码,开发者可以更深入地了解这...
在`pom.xml`文件中添加MyBatis和其与SpringBoot的适配器`spring-boot-starter-mybatis`: ```xml <!-- ...其他依赖... --> <groupId>org.mybatis.spring.boot <artifactId>mybatis-spring-boot-starter ...
以下是一个基本的配置示例: ```xml <!-- 数据源配置 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:...
4. **编写Mapper XML文件**:与Mapper接口相对应,我们需要创建XML文件来编写具体的SQL语句。在上述配置中,`mybatis.mapper-locations`指定了Mapper XML文件的位置。例如,`src/main/resources/mapper/UserMapper....
总结来说,Mybatis Plus的环境搭建主要包括引入依赖、配置数据源和Mybatis Plus参数,以及编写测试类验证其功能。理解并熟练运用Mybatis Plus,可以显著提升你在Java Web开发中的数据库操作效率。
总的来说,MyBatis Generator Core中文注解版1.3.5为Java开发者提供了一个高效且易用的代码生成解决方案,它降低了与数据库交互的复杂性,使得开发者能够更专注于业务逻辑的实现,提高了开发质量和效率。如果你是...
- `mybatis-config.xml`:MyBatis的配置文件。 5. **jdbc.properties文件**:配置数据库连接的基本信息。 示例内容如下: ``` driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/test...
通过学习和理解这个案例,开发者可以快速掌握Spring Boot与MyBatis的整合技巧,进而构建自己的数据驱动应用。这种整合方式在现代企业级应用中非常常见,因为它们结合了Spring Boot的便利性和MyBatis的灵活性,是开发...