【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】

时间:2022-05-06 06:33:11

一、动态SQL

  什么是动态SQL,就是在不同的条件下,sql语句不相同的意思,曾经在“酒店会员管理系统”中写过大量的多条件查询,那是在SSH的环境中,所以只能在代码中进行判断,以下是其中一个多条件查询的例子:

 public Collection<Card> getCardsByMN(int requestPage, String cardId,
String userName, String typeofcredential, String sex,
String integral) {
int m=(requestPage-1)*PageSplitConfig.pageSize;
int n=PageSplitConfig.pageSize;
String sql="from Card where 1=1 ";
if(cardId!=null&&!"".equals(cardId.trim())){
sql=sql+" and cardId='"+cardId.trim()+"'";
}
if(userName!=null&&!"".equals(userName.trim())){
sql=sql+" and userName='"+userName.trim()+"'";
}
if(typeofcredential!=null&&!"".equals(typeofcredential.trim())&&!"''".equals(typeofcredential.trim())){
sql=sql+" and credentialType.credentialTypeName='"+typeofcredential.trim()+"'";
}
if(sex!=null&&!"".equals(sex.trim())&&!"不限".equals(sex.trim())){
sql=sql+" and sex='"+sex+"'";
}
if(integral!=null&&!"".equals(integral.trim())){
sql=sql+" and integral='"+integral.trim()+"'";
}
return this.cardDao.getAllCards(sql,m,n);
}

  这是在Service方法中进行多条件的判断并最终形成多条件查询的SQL代码的方法,最终该SQL代码会被DAO执行。

  和这个形式非常相似,Mybatis中对这种情况充分做了考虑,它使用配置文件的方式以XML标签的形式对以上的逻辑进行了重新描述。

  在SSH环境中,由于Hibernate不支持动态SQL,所以只能在代码中进行SQL的动态拼接,这么做的弊端是显而易见的,而且该弊端在我的“酒店会员管理系统”中充分的暴露了出来。我的酒店会员管理系统中对对于日志的处理有两种形式,一种是多条件查询日志,一种是导出日志,这两个功能都涉及到了动态SQL拼接的问题,但是由于不是同一个Service方法,所以动态SQL的拼接必须重写两次,这就显得非常的麻烦,而且非常容易发生错误。但是如果使用Mybatis的话这种麻烦就会非常容易避免了。

  1.动态SQL之多条件查询

  这里的需求假设为:传入一个Student对象,程序会根据该对象属性值是否为空作为依据判断是否将该条件拼接到sql中;在映射文件中的配置方式和普通查询相比使用的标签都是select标签,但是里面需要使用mybatis中的逻辑判断标签进行判断:

<!-- 这里是动态查询的方法 -->
<select id="selectAllByCondition" parameterType="com.kdyzm.domain.Student"
resultMap="studentMap">
select * from student
<where>
<if test="id !=null">
and studentid=#{id}
</if>
<if test="name !=null">
and name=#{name}
</if>
<if test="age!=null">
and age=#{age}
</if>
<if test="password !=null">
and password=#{password}
</if>
</where>
</select>

    where标签是一个非常智能的标签,它能够通过不同的条件自动判断是否需要加上where关键字,如果你传入的对象中的属性值都为空,那么它就不会加上where关键字俄而且不需要使用where 1=1 这种写法;每个test中都需要加上and ,if标签也是智能标签,不赘述。

    java代码:

 String statement = "com.kdyzm.domain.Student.selectAllByCondition";
Student student = new Student();
student.setId(1);
// student.setAge(13);
List<Student> list = session.selectList(statement, student);
for (Student stu : list) {
System.out.println(stu);
}

  2.动态SQL之多条件更新

    其方法原理和多条件查询有诸多相似之处,不赘述。

 <!-- 这里是动态更新的方法 -->
<update id="updateStudentByCandition" parameterType="com.kdyzm.domain.Student">
update student
<set>
<!-- <if test="id!=null">
studentid=#{id}
</if> -->
<if test="name!=null">
name=#{name}
</if>
<if test="password!=null">
password=#{password}
</if>
<if test="age!=null">
age=#{age}
</if>
<if test="clazz!=null">
clazz=#{clazz}
</if>
</set>
where studentid=#{id}
</update>

    这里的动态sql的使用方法需要注意的事项:必须至少有一个字段不为空,否则就会报错;我本想着如果将以上代码中的注释部分放开的话就能够避免这种情况了,但是这只是理想状况,如果加上了id的判断,就会出错,原因未知。

二、mybatis和spring的整合

  项目源代码:https://github.com/kdyzm/day79_2_ssi

  mybatis框架的功能和hibernate功能相似,既然hibernate能够和spring整合并和struts框架整合之后形成所谓的SSH框架,那么mybatis框架能不能和spring、hibernate整合之后形成SSI框架呢?(Mybatis前身是Ibatis,到现在为止该框架中的很多包结构仍然采用ibatis的称呼,所以mybatis只是换了个名称而已,这里仍然使用SSI的称呼也只是从众而已),肯定是可以的。hibernate和Mybatis一样,就算没有spring也能够独立运行,但是既然要和spring整合了,那么Session对象的创建一定都交给了spring容器,这就需要一个中间的插件了,hibernate和spring整合的时候有一个org.springframework.orm-3.1.0.RELEASE.jar包,该jar包是hibernate和spring整合的关键,包括整合的过程中使用到的“本地会话工厂Bean”以及事务管理器,在该包中都有定义,spring发行版中会自带和hibernate整合相关的jar包,但是mybatis并没有这种待遇,mybatis为了能够为了和spring进行整合,它自己开发了和spring整合的jar包。这个jar包需要我们自己到网上下载。

  和spring整合需要的jar包的下载地址:https://github.com/mybatis/spring

  这里我是用了spring3.2的版本,有很多人习惯使用mybatis-spring-1.0.0版本的插件,但是在spring3.2版本下使用该插件的话会出现直接抛出某个异常,可以使用mybatis-spring-1.1.1版本的插件解决该异常,而且使用前者查询出来的结果需要强制类型转换,使用后者的时候就不需要进行强制类型转换。

  mybatis和spring整合的过程与hibernate和spring整合的过程几乎完全相同,有了hibernate和spring整合的经验,mybatis和spring整合就太简单了。

  第一步,加入所有需要的jar包。

    使用的spring的版本:spring3.2

    使用的数据库连接池:c3p0-0.9.5

    使用的mybatis版本:mybatis3.1.1

    使用的mybatis-spring版本:mybatis-spring-1.1.1

    这里就不和struts2进行整合了,实际上和struts2的整合就完全没有必须要了,实际上和struts2的整合还是和spring的整合,略。

    jar包一览图:

 c3p0-0.9.5.jar
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.apache.commons.codec-1.3.0.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.aspectj.tools-1.6.6.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
com.springsource.org.quartz-1.6.2.jar
commons-lang-2.5.jar
log4j.jar
mchange-commons-java-0.2.9.jar
mybatis-3.1.1.jar
mybatis-spring-1.1.1.jar
mysql-connector-java-5.1.18-bin.jar
org.springframework.aop-3.1.0.RELEASE.jar
org.springframework.asm-3.1.0.RELEASE.jar
org.springframework.aspects-3.1.0.RELEASE.jar
org.springframework.beans-3.1.0.RELEASE.jar
org.springframework.context-3.1.0.RELEASE.jar
org.springframework.context.support-3.1.0.RELEASE.jar
org.springframework.core-3.1.0.RELEASE.jar
org.springframework.expression-3.1.0.RELEASE.jar
org.springframework.jdbc-3.1.0.RELEASE.jar
org.springframework.orm-3.1.0.RELEASE.jar
org.springframework.transaction-3.1.0.RELEASE.jar
org.springframework.web-3.1.0.RELEASE.jar
org.springframework.web.servlet-3.1.0.RELEASE.jar
slf4j-api-1.5.8.jar
slf4j-log4j12.jar

整合需要的jar包

  第二步,准备数据源需要的配置文件

    这里使用jdbc.properties,将其放到classpath的根目录下

 jdbc.username=root
jdbc.password=5a6f38
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.driver=com.mysql.jdbc.Driver #C3p0 Configuration
c3p0.minPoolSize=2
c3p0.maxPoolSize=10
c3p0.initPoolSize=2
c3p0.increment=2

  第三步,不需要准备mybatis-config.xml配置文件

    因为该配置文件中需要配置的所有内容都转移到了spring中的配置文件中进行配置了。

  第四步,配置spring的配置文件,这里的配置过程和hibernate与spring整合的的配置过程几乎完全相同,不赘述。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx file:///D:\程序\java\Spring\spring-framework-4.2.1\spring-framework-4.2.1.RELEASE\schema/tx/spring-tx-2.5.xsd">
<context:component-scan base-package="com.kdyzm.dao"></context:component-scan>
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 第一步还是配置数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="driverClass" value="${jdbc.driver}"></property> <property name="initialPoolSize" value="${c3p0.initPoolSize}"></property>
<property name="minPoolSize" value="${c3p0.minPoolSize}"></property>
<property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property>
<property name="acquireIncrement" value="${c3p0.increment}"></property>
</bean>
<!-- 下一步,配置Session创建工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<!-- <property name="configLocation" value="classpath:mybatis-config.xml"></property> -->
<property name="mapperLocations">
<list>
<value>classpath:com/kdyzm/domain/Student.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
</beans>

    重点是黄色背景部分的配置,形式上和hibernate的和spring的整合过程一模一样,只是换了个类而已。

    以上没有配置事务,但是已经能够进行正常测试了。

    测试的过程略,想看直接到git中的相应项目中查看。

  第五步:事务的配置

  和hibernate和spring整合过程中事务的配置方式如出一辙,但是需要注意下面黄色背景部分的配置,事务管理器和hibernate使用的org.springframework.orm.hibernate3.HibernateTransactionManager是不相同的。

<!-- 事务的配置 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
<tx:method name="update*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
<tx:method name="new*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
<tx:method name="delete*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/> <tx:method name="get*" read-only="true"/>
<tx:method name="select*" read-only="true"/>
<tx:method name="find*" read-only="true"/> <!-- 其它方法默认全部加上事务 -->
<tx:method name="*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice> <aop:config>
<aop:pointcut expression="execution(* com.kdyzm.service.*.*(..))" id="txAop"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txAop"/>
</aop:config>

三、进行测试即可,测试使用的DAO/Service等在项目中。

  产生的疑问:保存Student对象的同时不能级联保存Clazz的问题,由于使用的是OGNL表达式,所以在前端页面中使用的Struts2的规则可以仿照这搬过来。

  测试代码:

StudentService service=(StudentService) context.getBean("studentService");
ClazzService clazzService=(ClazzService) context.getBean("clazzService");
Student student=new Student();
student.setId(8);
student.setName("小吧");
student.setPassword("xiaozhang");
student.setAge(120);
Clazz clazz=clazzService.getClazzById(2);
student.setClazz(clazz);
int result=service.saveStudent(student);
System.out.println("执行结果是:"+result);

  配置文件:

<insert id="insertIntoStudent" parameterType="com.kdyzm.domain.Student">
insert into
student(studentid,name,password,age,clazz)
values(#{id},#{name},#{password},#{age},#{clazz.id})
</insert>

  注意在这里的写法:如果直接写#{clazz},肯定直接报错,因为数据库中的字段类型是int类型,但是clazz在这里是Clazz对象。

【Java EE 学习 79 下】【动态SQL】【mybatis和spring的整合】的更多相关文章

  1. 【Java EE 学习 79 上】【mybatis 基本使用方法】

    一.简介 mybatis类似于hibernate,都是简化对数据库操作的框架,但是和hibernate不同的是,mybatis更加灵活,整体来说框架更小,这体现在它需要我们手写SQL语句,而hiber ...

  2. Java EE 学习(7):IDEA &plus; maven &plus; spring 搭建 web(3)- 配置数据库

    参考: https://my.oschina.net/gaussik/blog/513444 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 ...

  3. Java EE 学习(9):IDEA &plus; maven &plus; spring 搭建 web(5)- 博客文章管理

    转载:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) . 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 web(1) Jav ...

  4. Java EE 学习(8):IDEA &plus; maven &plus; spring 搭建 web(4)- 用户管理

    转载:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 注:在阅读本文前,请先阅读: Java EE 学习(5):IDEA + maven + spring 搭建 web(1) ava E ...

  5. Java EE 学习(6):IDEA &plus; maven &plus; spring 搭建 web(2)- 配置 Spring

    参考:https://my.oschina.net/gaussik/blog/513353 注:此文承接上一文:Java EE 学习(5):IDEA + maven + spring 搭建 web(1 ...

  6. Java EE 学习(5):IDEA &plus; maven &plus; spring 搭建 web(1)

    参考:http://www.cnblogs.com/lonelyxmas/p/5397422.html http://www.ctolib.com/docs-IntelliJ-IDEA-c--1590 ...

  7. 【Java EE 学习 67 下】【OA项目练习】【SSH整合JBPM工作流】【JBPM项目实战】

    一.SSH整合JBPM JBPM基础见http://www.cnblogs.com/kuangdaoyizhimei/p/4981551.html 现在将要实现SSH和JBPM的整合. 1.添加jar ...

  8. 【Java EE 学习 24 下】【注解在数据库开发中的使用】【反射&plus;注解&plus;动态代理在事务中的应用service层】

    一.使用注解可以解决JavaBean和数据库中表名不一致.字段名不一致.字段数量不一致的问题. 1.Sun公司给jdbc提供的注解 @Table.@Column.@Id.@OneToMany.@One ...

  9. 【Java EE 学习 75 下】【数据采集系统第七天】【二进制运算实现权限管理】【使用反射初始化权限表】【权限捕获拦截器动态添加权限】

    一.使用反射动态添加权限 在该系统中,我使用struts2的时候非常规范,访问的Action的形式都是"ActionClassName_MethodName.action?参数列表&quot ...

随机推荐

  1. ubuntu竖屏显示

    xrandr -o left 向左旋转90度 xrandr -o right 向右旋转90度 xrandr -o inverted 上下翻转 xrandr -o normal 回到正常角

  2. 密码学初级教程&lpar;五)消息认证码MAC-Message Authentication Code

    密码学家工具箱中的6个重要的工具: 对称密码 公钥密码 单向散列函数 消息认证码 数字签名 伪随机数生成器 MAC能识别出篡改和伪装,也就是既可以确认消息的完整性,也可以进行认证. 消息认证码的输入包 ...

  3. 由获取微信access&lowbar;token引出的Java多线程并发问题

    背景: access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.开发者需要进行妥善保存.access_token的存储至少要保留512个字符空间.acces ...

  4. 深入解析字符串的比较方法:&OpenCurlyDoubleQuote;&equals;&equals;”操作符;String&period;Equals方法;String&period;Compare方法;String&period;CompareOrdinal方法。

    1:要判断2个字符串变量是否相等,最高效的方法是看它们是否指向相同的内存地址.前面使用RefernceEquals方法来比较.如果2个变量指向的是不同的内存地址,那么就需要逐字符的比较2个字符串的变量 ...

  5. PHP正值表达式

    一个正值表达式是有四部分组成分别是 1.定界符 //是最常用的定界符 其实除了数组字母下划线以外其他的什么都可以作为定界符 2.原子:最小的一个匹配单位 放在定界符中  在一个正值表达式中至少要有一个 ...

  6. C&num;中的Invoke

    在用.NET Framework框架的WinForm构建GUI程序界面时,如果要在控件的事件响应函数中改变控件的状态,例如:某个按钮上的文本原先叫“打开”,单击之后按钮上的文本显示“关闭”,初学者往往 ...

  7. 【转】Java线程与Linux内核线程的映射关系

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  8. Solr DateRangeField

    Solr DateRangeField 是solr5.0 实现的一个feature. 关于 DateRangeField 支持日期查询如  date_field:[2016-03-23 TO 2017 ...

  9. 马斯克:有62&percnt;的程序员认为人工智能会被武器化 &num;精选AR人工智能算法

    当地时间 9 月 13 日,马斯克在自己的个人推特账号上转推了一篇名为<Hackers Have Already Started to Weaponize Artificial Intellig ...

  10. python 小练习 8

    砝码问题1有一组砝码,重量互不相等,分别为m1.m2.m3……mn:它们可取的最大数量分别为x1.x2.x3……xn. 现要用这些砝码去称物体的重量,问能称出多少种不同的重量. 现在给你两个正整数列表 ...