设为首页 收藏本站
查看: 925|回复: 0

[经验分享] mybatis编程事务管理参考一

[复制链接]

尚未签到

发表于 2016-11-25 08:48:41 | 显示全部楼层 |阅读模式
DSC0000.jpg  MyBatis与Spring集成示例续——MyBatis学习笔记之六

2012-08-06 23:53:25
标签:Spring 集成 MyBatis bean继承 编程式事务
DSC0001.png

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://legend2011.blog.iyunv.com/3018495/956585
      限于篇幅,MyBatis与Spring集成的一些细节在上篇博文中并未提及,今天继续。
一、引子
      前面的博文介绍了如何查询一个具有has-a关系的实体,今天就来看看如何向数据库中插入这样的一个实体。仍以学生为例,现在的问题是:学生实体把教师对象作为自己的指导教师属性,然而在学生表中,却仅有指导教师的ID一列,这如何映射呢?
      解决的方法其实很简单(这个方法是笔者猜出来的,哈哈,得瑟中…),关键在于在StudentMapper.xml中如下编写insert语句:
 

  • <insert id="add" parameterType="Student" 
  •         useGeneratedKeys="true" keyProperty="id"> 
  •           insert into student(name,gender,major,grade,supervisor_id)  
  •           values(#{name},#{gender},#{major},#{grade},#{supervisor.id})  
  •      </insert> 
       这里的关键是使用了supervisor.id这样的写法,这表明是把学生实体的supervisor属性的id属性值,作为插入的记录的supervisor_id字段的值。其他地方与之前的插入示例一致(MyBatis增删改示例)。
      当然在StudentMapper.java中插入实体的方法声明是少不了的,如下:
 

  • public void add(Student student); 
       执行程序如下:

  • package com.demo;  
  •  
  • import org.springframework.context.ApplicationContext;  
  • import com.abc.mapper.StudentMapper;  
  • import com.abc.domain.Student;  
  • import com.abc.domain.Teacher;  
  • import org.springframework.context.support.ClassPathXmlApplicationContext;  
  •  
  • public class MyBatisSpringDemo  
  • {  
  •     private static ApplicationContext ctx;  
  •       
  •     static 
  •     {  
  •         //在类路径下寻找resources/beans.xml文件  
  •         ctx = new ClassPathXmlApplicationContext("resources/beans.xml");  
  •     }  
  •       
  •       
  •     public static void main(String[] args)  
  •     {  
  •         StudentMapper mapper =   
  •                (StudentMapper)ctx.getBean("studentMapper");  
  •  
  •         Student student = new Student();  
  •  
  •         student.setName("李林");  
  •         student.setGender("男");  
  •         student.setMajor("计算机科学与技术");  
  •         student.setGrade("2011");  
  •         Teacher supervisor = new Teacher();  
  •         supervisor.setId(1);  
  •         student.setSupervisor(supervisor);  
  •           
  •         mapper.add(student);  
  •           
  •     }  
  •  

       执行后,登录MySQL查询。如下图所示:
DSC0002.png

 (注:第一个红框里的命令“set names gbk”是为了能够显示中文。)

      从第二个和第三个红框之间的对比可以看出,数据已被写入到数据库(点此进入无事务处理的源码下载页面)。
二、事务管理
     在上面的示例中,并没有为程序配置事务管理器,而在程序中也不像以前的示例那样调用了提交事务的方法,但数据却已实实在在地被写入到了数据库中。这是怎么回事呢?mybatis官方文档告诉我们,凡是在Spring事务之外执行的映射器方法,都会被自动提交(英文可参见http://www.mybatis.org/spring/transactions.html中的“Programmatic Transaction Management”部分,中文可参见http://www.mybatis.org/spring/zh/transactions.html中的“编程式事务管理”部分)。这样一来,就没有用上Spring强大的事务管理功能。Spring事务管理提供声明式(declarative)和编程式(programmatic)两种方式。今天就先给大家介绍一下编程式的基本用法(虽然声明式是最常用的方式,但是发现想把它说清楚不是那么容易滴,留待以后有机会再详述吧)。
      首先在Spring的配置文件(本例中为beans.xml)中配置MyBatis-Spring要用到的事务管理器,即org.springframework.jdbc.datasource.DataSourceTransactionManager。配置内容如下: 
 

  • <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
  •   <property name="dataSource" ref="dataSource" /> 
  • </bean> 
      在这里,事务管理器引用了在前面配置的数据源dataSource。显而易见,这个数据源必须是事务管理器所管理的事务将要操作的那个数据源。也就是说,应该与SqlSessionFactoryBean引用同一个数据源。因为我们正是由SqlSessionFactoryBean来获得映射器,进而调用映射器的方法来对数据库进行操作。
      需要注意的是,Spring对事务管理做了抽象,提供了统一的编程接口。例如上述的DataSourceTransactionManager事务管理器,实际上是实现了接口org.springframework.transaction.PlatformTransactionManager。针对不同的环境,Spring提供了不同的实现。例如,对于Hibernate,可使用事务管理器org.springframework.orm.hibernate3.HibernateTransactionManager。与此相关的接口还有org.springframework.transaction.TransactionDefinition和org.springframework.transaction.TransactionStatus,分别代表事务的定义和事务的状态。提供统一接口的好处是我们只需要针对这个接口编程,而无需考虑不同环境下事务处理的不同细节。
      编程式事务管理代码如下:

  • package com.demo;  
  •  
  • import org.springframework.context.ApplicationContext;  
  • import com.abc.mapper.StudentMapper;  
  • import com.abc.domain.Student;  
  • import com.abc.domain.Teacher;  
  • import org.springframework.context.support.ClassPathXmlApplicationContext;  
  • import org.springframework.transaction.support.DefaultTransactionDefinition;  
  • import org.springframework.transaction.TransactionDefinition;  
  • import org.springframework.transaction.TransactionStatus;  
  • import org.springframework.transaction.PlatformTransactionManager;  
  • import org.springframework.jdbc.datasource.DataSourceTransactionManager;  
  •  
  • public class MyBatisSpringDemo  
  • {  
  •     private static ApplicationContext ctx;  
  •       
  •     static 
  •     {  
  •         //在类路径下寻找resources/beans.xml文件  
  •         ctx = new ClassPathXmlApplicationContext("resources/beans.xml");  
  •     }  
  •       
  •       
  •     public static void main(String[] args)  
  •     {  
  •         //从Spring容器中请求映射器  
  •         StudentMapper mapper =   
  •                (StudentMapper)ctx.getBean("studentMapper");  
  •  
  •         //从Spring容器中请求事务管理器,用PlatformTransactionManager  
  •         //类型的引用指向它  
  •         PlatformTransactionManager tm =  
  •                (PlatformTransactionManager)ctx.getBean("transactionManager");  
  •  
  •         Student student = new Student();  
  •         student.setName("王芳");  
  •         student.setGender("女");  
  •         student.setMajor("计算机科学与技术");  
  •         student.setGrade("2011");  
  •         Teacher supervisor = new Teacher();  
  •         supervisor.setId(1);  
  •         student.setSupervisor(supervisor);  
  •           
  •         //TransactionDefinition对象代表着事务的定义,即事务的传播行为,  
  •         //隔离级别和是否可读等属性。DefaultTransactionDefinition是此  
  •         //接口的默认实现,给上述属性指定了默认值。如传播行为是PROPAGATION_REQUIRED,  
  •         //只读为false等(可参见Spring api文档)  
  •         TransactionDefinition def = new DefaultTransactionDefinition();  
  •           
  •         //TransactionStatus对象代表着事务的状态。以下代码根据传入的事务定义  
  •         //对象返回事务并启动事务  
  •         TransactionStatus status = (TransactionStatus)tm.getTransaction(def);  
  •  
  •         try {  
  •            mapper.add(student);  
  •            //若执行下述语句,则事务回滚。  
  •            //读者可自行验证  
  •            //int a = 1/0;  
  •             }  
  •         catch (Exception e) {  
  •            //回滚事务  
  •            tm.rollback(status);  
  •            e.printStackTrace();  
  •         }  
  •  
  •         //提交事务  
  •         tm.commit(status);  
  •           
  •     }  
  •  

      执行结果如下:
DSC0003.png
       查询数据库如下图所示:
DSC0004.png

       显然,数据已被写入。
三、使用bean继承配置映射器
      当我们需要在beans.xml中配置多个映射器时,它们的class和sqlSessionFactory属性都是一样的(也许还有其它一样的属性)。显然,我们需要消除这种冗余信息。借助于bean继承机制,我们可以达到这个目的。如下所示:

  • <bean id="parentMapper" class="org.mybatis.spring.mapper.MapperFactoryBean" 
  •    abstract="true"> 
  •      <!--sqlSessionFactory属性指定要用到的SqlSessionFactory实例--> 
  •      <property name="sqlSessionFactory" ref="sqlSessionFactory" /> 
  •   </bean> 
  •  
  •   <bean id="studentMapper" parent="parentMapper"> 
  •      <!--mapperInterface属性指定映射器接口,用于实现此接口并生成映射器对象--> 
  •      <property name="mapperInterface" value="com.abc.mapper.StudentMapper" /> 
  • </bean> 
      这里的关键是把父bean parentMapper的abstract属性指定为true。这样,Spring就不会创建这个bean实例。它存在的意义是配置好class和sqlSessionFactory这两个属性,供其他子bean继承。而子bean通过把parent属性设置为parentMapper,即可继承这两个属性(点此进入有编程式事务处理和bean继承的源码)。
【MyBatis学习笔记】系列之预备篇一:ant的下载与安装
【MyBatis学习笔记】系列之预备篇二:ant入门示例
【MyBatis学习笔记】系列之一:MyBatis入门示例
【MyBatis学习笔记】系列之二:MyBatis增删改示例
【MyBatis学习笔记】系列之三:MyBatis的association示例
【MyBatis学习笔记】系列之四:MyBatis association的两种形式
【MyBatis学习笔记】系列之五:MyBatis与Spring集成示例
【MyBatis学习笔记】系列之六:MyBatis与Spring集成示例续
【MyBatis学习笔记】系列之七:MyBatis一对多双向关联
【MyBatis学习笔记】系列之八:MyBatis MapperScannerConfigurer配置
【MyBatis学习笔记】系列之九:MyBatis collection的两种形式
【MyBatis学习笔记】系列之十:MyBatis日志之Log4j示例
【MyBatis学习笔记】系列之十一:MyBatis多参数传递之注解方式示例
【MyBatis学习笔记】系列之十二:MyBatis多参数传递之默认命名方式示例
【MyBatis学习笔记】系列之十三:MyBatis多参数传递之Map方式示例
【MyBatis学习笔记】系列之十四:MyBatis中的N+1问题
【MyBatis学习笔记】系列之十五:MyBatis多参数传递之混合方式
本文出自 “肖凡的专栏” 博客,请务必保留此出处http://legend2011.blog.iyunv.com/3018495/956585

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-305215-1-1.html 上篇帖子: mybatis复杂查询例子 下篇帖子: 万恶的Mybatis的EnumTypeHandler
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表