Mybatis动态SQL
一:背景介绍
项目开发中。我们使用的是MyBatis,在MyBatis的xml文件里,两个表的更新功能,写了足足11个更新接口,毫无复用的思想这种方式可以正常的实现功能,但是没有复用,无论是从时间上还是维护性上,都会增加额外的成本。
那么我们该如何解决这个问题呢?如何写出可以复用的语句呢?在下面的例子里我会给大家进行展示 !!
二:前期准备
我们需要准备一个使用MyBatis的maven项目。大家需要提前准备好Mysql数据库
2.1 引入pom依赖
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
这里我们只需要引入mysql,mybatis,junit测试三个依赖即可,这三个依赖就足够我们对本次讲解进行测试。
2.2 数据库连接文件
引入之后我们要配置一些数据库的连接问题
这里注意将自己数据库机器的ip地址和对应的库名写对,不然无法连接自己的数据库。我这里隐藏了自己的ip地址,大家改成自己的即可。
2.3 MyBatis配置文件
因为我们使用的是普通的maven项目,所以需要写对应的配置文件,进行配置。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"> <!--configuration mybatis的核心配置文件--> <configuration> <!--引入外部配置文件--> <properties resource="db.properties"/> <!--配置--> <settings> <!--标准日志工厂设置--> <setting name="logImpl" value="STDOUT_LOGGING"/> <!--显示的开启全局缓存--> <setting name="cacheEnabled" value="true"/> </settings> <!--可以给实体类取别名--> <typeAliases> <!--可以指定一个包名,MyBatis会在包名下面搜索需要的Java Bean--> <package name="org.example.pojo"/> </typeAliases> <!--environments 后面的s表示这是一个复数,可以编写多套环境 default表示默认的环境为development--> <environments default="development"> <!--编写一套环境 名称为configuration--> <environment id="development"> <!--jdbc的事务管理--> <transactionManager type="JDBC"/> <!--配置数据库相关数据--> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <!--userSSL是一个按权连接 &是一个转移符 等同于and CharacterEncoding=utf-8可以保证输入数据库的数据不乱码--> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!--绑定接口--> <mappers> <mapper class="org.example.dao.UserCourseGroupConfigurationMapper"/> </mappers> </configuration>
2.4 MyBatis配置类
编写对应的配置类,让我们的项目在启动的时候读取对应的配置文件。
public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; //静态代码块:一旦初始化就加载 static{ try { //使用Mybatis第一步:获取sqlSessionFactory对象 //获取资源,直接读到mybatis-config.xml String resource = "mybatis-config.xml"; //需要用到输入流(InputStream) 把resource类加载进来 InputStream inputStream = Resources.getResourceAsStream(resource); //通过build把输入流加载进来 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { //openSession中有自动commit(提交)事务的方法,加上true就能实现 return sqlSessionFactory.openSession(true); } }
到这里,我们的基本环境就准备好了,可以进行代码的编写。
三:通用的更新语句
我写了一个通用的更新语句,将这个语句写好之后,我们可以去上文提到的,两张表 11个更新接口其中一个写了9个更新接口的mapper.xml文件,看一看这个通用的mapper能够覆盖到多少个。
3.1 通用update语句
<update id="updateCourseGroupConfiguration"> update arpro_user_course_group_configuration <trim prefix="SET" suffixOverrides=","> <if test="reviseParam.infoId != null">info_id = #{reviseParam.infoId}</if> <if test="reviseParam.courseId != null">course_id = #{reviseParam.courseId}</if> <if test="reviseParam.classId != null">class_id = #{reviseParam.classId}</if> <if test="reviseParam.groupId != null">group_id = #{reviseParam.groupId}</if> <if test="reviseParam.type != null">type = #{reviseParam.type}</if> <if test="reviseParam.isDelete != null">is_delete = #{reviseParam.isDelete}</if> <if test="reviseParam.remark != null">remark = #{reviseParam.remark}</if> <if test="reviseParam.isMostLike != null">is_like = #{reviseParam.isLike}</if> </trim> where is_delete = 0 <if test="conditionParam.infoId != null"> and info_id = #{conditionParam.infoId}</if> <if test="conditionParam.courseId != null">and course_id = #{conditionParam.courseId}</if> <if test="conditionParam.classId != null">and class_id = #{conditionParam.classId}</if> <if test="conditionParam.groupId != null">and group_id = #{conditionParam.groupId}</if> <if test="conditionParam.isMostLike != null">and is_like = #{conditionParam.isLike}</if> <if test="conditionParam.type != null">and type = #{conditionParam.type}</if> </update>
3.2 可以覆盖的更新接口
<update id="updateGroupRelationship"> UPDATE arpro_user_course_group_configuration set group_id = #{newGroupId} WHERE group_id = #{oldGroupId} and type = #{type} </update> <update id="updateGroupIsDelete"> UPDATE arpro_user_course_group_configuration SET is_delete=1 WHERE class_id = #{classId} AND course_id = #{courseId} </update> <update id="updateGroupIsDeleteByCourseId"> UPDATE arpro_user_course_group_configuration SET is_delete=1 WHERE course_id = #{courseId} </update> <update id="updateGroupRelationshipByClassIdAndCourseId"> UPDATE arpro_user_course_group_configuration set group_id = #{groupCourseModel.newGroupId} ,is_like = #{isLike} WHERE type = #{groupCourseModel.type} and class_id = #{groupCourseModel.classId} and course_id = #{groupCourseModel.courseId} and info_id =#{groupCourseModel.infoId} </update> <update id="updateCourseIsLike" parameterType="com.tfjy.arprobackend.model.GroupCourseModel"> UPDATE arpro_user_course_group_configuration set is_like = #{isLike} where group_id = #{groupId} and type = #{type} </update> <update id="updateUserCourseIsLike"> UPDATE arpro_user_course_group_configuration set is_like = 1 where info_id = #{infoId} and type = #{type} and group_id != #{groupId} and is_delete = 0 </update> <update id="updateUserCourseNotLike"> UPDATE arpro_user_course_group_configuration set is_like = 0 where info_id = #{infoId} and type = #{type} and group_id = #{groupId} and is_delete = 0 </update> <update id="updateGroupRelation"> UPDATE arpro_user_course_group_configuration set group_id = #{newGroupId} ,info_id = #{newInfoId} WHERE type = 1 and class_id = #{classId} and course_id = #{courseId} and info_id = #{oldInfoId} </update>
3.3 暂时无法覆盖到的更新接口
<update id="updateGroupIsDeleteByUserId"> update `arpro_user_course_group_configuration` set is_delete =1 WHERE course_id=#{courseAndStudentInfoModel.courseId} AND class_id=#{courseAndStudentInfoModel.classId} AND info_id IN <foreach item="student" collection="studentList" open="(" separator="," close=")"> #{student} </foreach> </update>
3.4 测试方法
@Test public void test(){ //获取数据库连接 SqlSession sqlSession = MybatisUtils.getSqlSession(); UserCourseGroupConfigurationMapper userCourseGroupConfigurationMapper = sqlSession.getMapper(UserCourseGroupConfigurationMapper.class); //进行更新操作 UserCourseGroupConfigurationPojo reviseParam = new UserCourseGroupConfigurationPojo(); UserCourseGroupConfigurationPojo conditionParam = new UserCourseGroupConfigurationPojo(); //假删除某个课的某个班的所有信息 reviseParam.setIsDelete(1); conditionParam.setCourseId(BigInteger.valueOf(223667994)); conditionParam.setClassId(BigInteger.valueOf(56496292)); //进行调用 userCourseGroupConfigurationMapper.updateCourseGroupConfiguration(reviseParam,conditionParam); }
3.5 分析
从结果上来看,二者的对比是惊人的。一个通用的更新接口,竟然覆盖了我写的更新的9个接口中的8个。
也就是说,在之前的开发中,造了7个重复的轮子。并且至少多了7处使用这些sql语句的地方,多了7个需要维护的代码。
复用思想多么的重要啊,没有这种思想,写一些重复的代码,不但效率低,时间长,还加大了出错的可能。
四:总结
写代码的时候,一定,一定,一定,要考虑维护的问题,考虑复用的问题。这样我们写出的代码才能不仅可以实现功能,而且还容易维护。
接下来我的文章内还会系统的去总结MyBatis的动态sql的写法,大家有兴趣可以持续关注。