进入QQ游戏命令提示符diyec8.1ssm是什么

1、开发对比开发速度&p&Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。个人觉得要用好Mybatis还是首先要先理解好Hibernate。&/p&开发社区&p&Hibernate 与Mybatis都是流行的持久层开发框架,但Hibernate开发社区相对多热闹些,支持的工具也多,更新也快,当前最高版本4.1.8。而Mybatis相对平静,工具较少,当前最高版本3.2。&/p&开发工作量&p&Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。&/p&&p&针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。&/p&2、系统调优对比Hibernate的调优方案&ol&&li&制定合理的缓存策略;&/li&&li&尽量使用延迟加载特性;&/li&&li&采用合理的Session管理机制;&/li&&li&使用批量抓取,设定合理的批处理参数(batch_size);&/li&&li&进行合理的O/R映射设计&/li&&/ol&Mybatis调优方案&p&MyBatis在Session方面和Hibernate的Session生命周期是一致的,同样需要合理的Session管理机制。MyBatis同样具有二级缓存机制。 MyBatis可以进行详细的SQL优化设计。&/p&SQL优化方面&p&Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。&/p&&p&Hibernate HQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Log4j进行日志记录。&/p&扩展性方面&p&Hibernate与具体数据库的关联只需在XML文件中配置即可,所有的HQL语句与具体使用的数据库无关,移植性很好。MyBatis项目中所有的SQL语句都是依赖所用的数据库的,所以不同数据库类型的支持不好。&/p&3、对象管理与抓取策略对象管理&p&Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的 JDBC/SQL 持久层方案中需要管理 SQL 语句,Hibernate采用了更自然的面向对象的视角来持久化 Java 应用中的数据。&/p&&p&换句话说,使用 Hibernate 的开发者应该总是关注对象的状态(state),不必考虑 SQL 语句的执行。这部分细节已经由 Hibernate 掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。&/p&&p&而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。&/p&抓取策略&p&Hibernate对实体关联对象的抓取有着良好的机制。对于每一个关联关系都可以详细地设置是否延迟加载,并且提供关联抓取、查询抓取、子查询抓取、批量抓取四种模式。 它是详细配置和处理的。&/p&&p&而Mybatis的延迟加载是全局配置的。&/p&4、缓存机制对比Hibernate缓存&p&Hibernate一级缓存是Session缓存,利用好一级缓存就需要对Session的生命周期进行管理好。建议在一个Action操作中使用一个Session。一级缓存需要对Session进行严格管理。&/p&&p&Hibernate二级缓存是SessionFactory级的缓存。 SessionFactory的缓存分为内置缓存和外置缓存。内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定SQL语句等),对于应用程序来说,它是只读的。外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备。二级缓存称为进程级缓存或SessionFactory级缓存,它可以被所有session共享,它的生命周期伴随着SessionFactory的生命周期存在和消亡。&/p&&p&5、优势对比&/p&Mybatis优势&ul&&li&MyBatis可以进行更为细致的SQL优化,可以减少查询字段。&/li&&li&MyBatis容易掌握,而Hibernate门槛较高。&/li&&/ul&Hibernate优势&ul&&li&Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。&/li&&li&Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。&/li&&li&Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。&/li&&li&Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。&/li&&/ul&&p&来源:麦子学院&/p&
1、开发对比开发速度Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。个人觉得要用好Mybatis还是首先要先理解好Hibernate。开发社区Hibernate 与Mybatis都是流行的持久层开发框架,但Hibernate开发社区相对多热闹…
推荐Spring boot,开发快,文档全,方便部署,解放生产力。让人能花更多的时间在构思与业务逻辑上。&br&另外,SSH里的Struts我是很讨厌的...&br&&br&Spring Boot上手难吗…?看不懂官方文档的话,我们跟着教程走呗&br&&a href=&//link.zhihu.com/?target=https%3A//course.tianmaying.com/web-development& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&course.tianmaying.com/w&/span&&span class=&invisible&&eb-development&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&&br&真心觉得比Spring MVC简单..&br&&br&你们评论区别把Spring Boot简称成s[友善]b啊,会被折叠的!
推荐Spring boot,开发快,文档全,方便部署,解放生产力。让人能花更多的时间在构思与业务逻辑上。 另外,SSH里的Struts我是很讨厌的... Spring Boot上手难吗…?看不懂官方文档的话,我们跟着教程走呗
&p&关于ssm整合框架的学习,我在github上上传过一个小例子就是对商品信息的增删改查,通过这些操作会让你快速学习通过ssm整合框架开发项目,里面README.md详细介绍了开发流程,附上链接:
&a href=&//link.zhihu.com/?target=https%3A//github.com/codingXiaxw/ssm.git& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&codingXiaxw/ssm&i class=&icon-external&&&/i&&/a&
希望对你的学习有帮助。
&/p&&p&&br&&/p&&p&另外我这边还有自己在java学习道路上写的几个很值得锻炼的小项目(都是干货哦),如下:&/p&&p&作者:codingXiaxw
链接:&a href=&https://www.zhihu.com/question//answer/& class=&internal&&求Github上质量较好的java web项目?想fork下下&/a&
来源:知乎
著作权归作者所有,转载请联系作者获得授权。&/p&&p&我写过一个客户管理系统,由于当时没有接触框架所以使用到的技术就是JSP+Servlet+Mysql,另外对查询到的信息我使用了分页的技术,用的开发工具的IDEA,博客上详细讲解了操作流程,附上博客链接: &a href=&https://www.zhihu.com/question//answer/& class=&internal&&JavaWeb项目之客户管理系统&/a&
,源码链接为 &a href=&https://www.zhihu.com/question//answer/& class=&internal&&codingXiaxw/CustomerManagement&/a&
目前已经在github上得到500+个star和350+个fork。&/p&&p&学了SSM框架后做了一个对商品信息增删改查的项目,包括SSM框架的整合详细教程,github上已经上传了我的源代码以及在README.md和博客中详细介绍了 SSM框架整合以及利用SSM框架进行开发这个项目的步骤,在此附上github链接(github的REAMDE.md中有我项目对应的博客链接,目前已经得到300个star和100+个fork)
&a href=&https://www.zhihu.com/question//answer/& class=&internal&&codingXiaxw/ssm&/a&
另外还有在此项目上进一步进行的SSM高级知识的开发(目前已经得到200+个star和200+个fork),github源码和详细教程链接:
&a href=&https://www.zhihu.com/question//answer/& class=&internal&&codingXiaxw/ssm2&/a&&/p&&p&学习了Shiro框架以后,我又写了一个利用Shiro+SSM框架在上述利用SSM框架开发项目中搭建了Shiro框架,用于进行用户登录的认证以及权限管理,github上传了详细教程以及源码(目前得到200+个star和200+个fork),附上github链接: &a href=&https://www.zhihu.com/question//answer/& class=&internal&&codingXiaxw/shiro&/a&&/p&&p&学习了Maven对项目进行管理后,又利用Maven+SSM做了一个高并发的秒杀系统,源码和详细讲解已经上传到github(目前得到500+个star和400+fork),附上源码链接
&a href=&https://www.zhihu.com/question//answer/& class=&internal&&codingXiaxw/seckill&/a&&/p&&p&等做完上面的项目,基本对SSM框架和Maven管理工具有了基本的掌握。有人会觉得还有项目练习吗?我想说项目多的是(就比如说我就还有很多高级的项目,例如我做过一个BBS论坛系统,目前源代码没上传,想要的可以在底下留言或者私我)。比如上面那个客户管理系统,这时你不妨利用学习的SSM框架和Maven对上面的客户管理系统重新进行一次开发吧!&/p&&p&另外我想说的是,我在我的github上看到很多伸手党对上述提到的项目只fork不star。我比较郁闷,题主辛辛苦苦给你们将开发文档写的那么详细,就不能在fork的同时点下star吗...
&/p&&p&很多大神都说过这样一句话:&收藏请点击star不要fork&,我不知道你懂不懂,反正我现在是懂了。这样跟你解释吧,你fork过去的项目源代码只是目前题主上传到github的源代码,万一你fork完后题主对源代码又进行了更改,那么不好意思,更改的源代码并不会和你fork过去的同时更改,也就是若是题主对源代码进行了更新或是维护,那么你那边fork过去的源代码是不会同时更新的(也就是说你可能fork的是过期的项目)。
但是star就不一样了,github上会将你star过的项目都收集在你的star列表里,这样当你需要用的时候就可以随时点击过去查看最新的源代码了。&/p&&p&所以说呢,收藏最好点star不要fork,但如果你要是想将项目在自己的电脑上跑起来的话就在star的同时将该项目fork到你自己的仓库中吧!。
&/p&&p&最后,祝你好运。&/p&&p&&br&&/p&&p&===============更===========&/p&&p&在很多道友的提议下,我开了一个Java的学习交流群:。话不多说,赶快上车吧!&/p&
关于ssm整合框架的学习,我在github上上传过一个小例子就是对商品信息的增删改查,通过这些操作会让你快速学习通过ssm整合框架开发项目,里面README.md详细介绍了开发流程,附上链接:
希望对你的学习有帮助。 另外我这边还有自己在java学习…
&blockquote&&b&&i&来源:&a href=&http://link.zhihu.com/?target=http%3A//www.jianshu.com/p/fb3ec1184aa6& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&jianshu.com/p/fb3ec1184&/span&&span class=&invisible&&aa6&/span&&span class=&ellipsis&&&/span&&/a&&/i&&/b&&p&&b&&i&作者:方志朋&/i&&/b&&/p&&/blockquote&&p&&b&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&上一篇&/a&&/b&讲述了DAO 层,mybatis实现数据库的连接,DAO层接口设计,以及mybtis和spring的整合。DAO层采用接口设计方式实现,接口和SQL实现的分离,方便维护。DAO层所负责的仅仅是接口的设计和实现,而负责的逻辑即一个或多个DAO层接口的拼接是在Sevice层中完成。这篇文章接上篇文章,主要讲述Service层的实现、和Spring的整合以及声明如何声明事物。&/p&&h3&&b&一、Service层接口设计&/b&&/h3&&p&业务接口设计应当站在“使用者”角度设计接口,应遵循三个规范:合理的命令,明确的参数,返回结果(正常接口/异常结果)。本例子采用的Java高并发的秒杀API系列课程的例子,创建设计的业务逻辑接口如下:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kd&&public&/span& &span class=&kd&&interface&/span& &span class=&nc&&SeckillService&/span& &span class=&o&&{&/span&
&span class=&cm&&/**&/span&
&span class=&cm&&
* 查询所有秒杀记录&/span&
&span class=&cm&&
* @return&/span&
&span class=&cm&&
&span class=&n&&List&/span&&span class=&o&&&&/span&&span class=&n&&Seckill&/span&&span class=&o&&&&/span& &span class=&nf&&getSerkillList&/span&&span class=&o&&();&/span&
&span class=&cm&&/**&/span&
&span class=&cm&&
* 查询单个秒杀记录&/span&
&span class=&cm&&
* @param seckillId&/span&
&span class=&cm&&
* @return&/span&
&span class=&cm&&
&span class=&n&&Seckill&/span& &span class=&nf&&getById&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&cm&&/**&/span&
&span class=&cm&&
* 秒杀开启时输出秒杀接口地址,&/span&
&span class=&cm&&
* 否则输出系统时间和秒杀时间&/span&
&span class=&cm&&
* @param seckillId&/span&
&span class=&cm&&
&span class=&n&&Exposer&/span& &span class=&nf&&exportSeckillUrl&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&err&&/&/span&&span class=&o&&**&/span&
&span class=&o&&*&/span&&span class=&n&&执行秒杀接口&/span&
&span class=&o&&*/&/span&
&span class=&n&&SeckillExecution&/span& &span class=&nf&&executeSeckill&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&,&/span& &span class=&kt&&long&/span& &span class=&n&&userPhone&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&md5&/span&&span class=&o&&)&/span& &span class=&kd&&throws&/span& &span class=&n&&SeckillException&/span&&span class=&o&&,&/span&&span class=&n&&RepeatKillException&/span&&span class=&o&&,&/span&&span class=&n&&SeckillCloseException&/span&&span class=&o&&;&/span&
&/code&&/pre&&/div&&h3&&b&二、Service接口的实现&/b&&/h3&&p&直接上代码了,在这里讲下秒杀业务的逻辑:首先是获取秒杀列表,点击列表进入秒杀详情页,这时获取系统时间,如果秒杀开始,获取秒杀地址,点击秒杀,执行秒杀。所以业务逻辑也只设计了这相关的4个业务逻辑。其中使用了dto层去传递响应数据,以及自定义异常,所有的异常都继承运行异常,这是为了方便spring自动回滚,这两个知识点,自行看源码。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&kn&&package&/span& &span class=&nn&&org.forezp.service.impl&/span&&span class=&o&&;&/span&
&span class=&nd&&@Service&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&SeckillServiceImpl&/span& &span class=&kd&&implements&/span& &span class=&n&&SeckillService&/span&&span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&Logger&/span& &span class=&n&&logger&/span&&span class=&o&&=&/span& &span class=&n&&LoggerFactory&/span&&span class=&o&&.&/span&&span class=&na&&getLogger&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&getClass&/span&&span class=&o&&());&/span&
&span class=&c1&&//注入service依赖&/span&
&span class=&nd&&@Autowired&/span&
&span class=&kd&&private&/span& &span class=&n&&SeckillDao&/span& &span class=&n&&seckillDao&/span&&span class=&o&&;&/span&
&span class=&nd&&@Autowired&/span&
&span class=&kd&&private&/span& &span class=&n&&SuccessKilledDao&/span& &span class=&n&&successKilledDao&/span&&span class=&o&&;&/span&
&span class=&c1&&//MD5盐值字符串,用户混淆MD5&/span&
&span class=&kd&&private&/span& &span class=&kd&&final&/span& &span class=&n&&String&/span& &span class=&n&&slat&/span&&span class=&o&&=&/span&&span class=&s&&&sfsa=32q4rERWERT^**%^SDF&&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&n&&List&/span&&span class=&o&&&&/span&&span class=&n&&Seckill&/span&&span class=&o&&&&/span& &span class=&nf&&getSerkillList&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&seckillDao&/span&&span class=&o&&.&/span&&span class=&na&&queryAll&/span&&span class=&o&&(&/span&&span class=&mi&&0&/span&&span class=&o&&,&/span&&span class=&mi&&4&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&Seckill&/span& &span class=&nf&&getById&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&seckillDao&/span&&span class=&o&&.&/span&&span class=&na&&queryById&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&Exposer&/span& &span class=&nf&&exportSeckillUrl&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&Seckill&/span& &span class=&n&&seckill&/span& &span class=&o&&=&/span&&span class=&n&&seckillDao&/span&&span class=&o&&.&/span&&span class=&na&&queryById&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&seckill&/span&&span class=&o&&==&/span&&span class=&kc&&null&/span&&span class=&o&&){&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&Exposer&/span&&span class=&o&&(&/span&&span class=&kc&&false&/span&&span class=&o&&,&/span&&span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&n&&Date&/span& &span class=&n&&startTime&/span&&span class=&o&&=&/span&&span class=&n&&seckill&/span&&span class=&o&&.&/span&&span class=&na&&getStartTime&/span&&span class=&o&&();&/span&
&span class=&n&&Date&/span& &span class=&n&&endTime&/span&&span class=&o&&=&/span&&span class=&n&&seckill&/span&&span class=&o&&.&/span&&span class=&na&&getEndTime&/span&&span class=&o&&();&/span&
&span class=&c1&&//系统当前时间&/span&
&span class=&n&&Date&/span& &span class=&n&&nowTime&/span&&span class=&o&&=&/span&&span class=&k&&new&/span& &span class=&n&&Date&/span&&span class=&o&&();&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&nowTime&/span&&span class=&o&&.&/span&&span class=&na&&getTime&/span&&span class=&o&&()&&/span&&span class=&n&&startTime&/span&&span class=&o&&.&/span&&span class=&na&&getTime&/span&&span class=&o&&()||&/span&&span class=&n&&nowTime&/span&&span class=&o&&.&/span&&span class=&na&&getTime&/span&&span class=&o&&()&&/span&&span class=&n&&endTime&/span&&span class=&o&&.&/span&&span class=&na&&getTime&/span&&span class=&o&&()){&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&Exposer&/span&&span class=&o&&(&/span&&span class=&kc&&false&/span&&span class=&o&&,&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&nowTime&/span&&span class=&o&&.&/span&&span class=&na&&getTime&/span&&span class=&o&&(),&/span&&span class=&n&&startTime&/span&&span class=&o&&.&/span&&span class=&na&&getTime&/span&&span class=&o&&(),&/span&&span class=&n&&endTime&/span&&span class=&o&&.&/span&&span class=&na&&getTime&/span&&span class=&o&&());&/span&
&span class=&o&&}&/span&
&span class=&n&&String&/span& &span class=&n&&md5&/span&&span class=&o&&=&/span&&span class=&n&&getMD5&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&Exposer&/span&&span class=&o&&(&/span&&span class=&kc&&true&/span&&span class=&o&&,&/span&&span class=&n&&md5&/span&&span class=&o&&,&/span&&span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&nf&&getMD5&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&){&/span&
&span class=&n&&String&/span& &span class=&n&&base&/span&&span class=&o&&=&/span&&span class=&n&&seckillId&/span&&span class=&o&&+&/span&&span class=&s&&&/&&/span&&span class=&o&&+&/span&&span class=&n&&slat&/span&&span class=&o&&;&/span&
&span class=&n&&String&/span& &span class=&n&&md5&/span&&span class=&o&&=&/span& &span class=&n&&DigestUtils&/span&&span class=&o&&.&/span&&span class=&na&&md5DigestAsHex&/span&&span class=&o&&(&/span&&span class=&n&&base&/span&&span class=&o&&.&/span&&span class=&na&&getBytes&/span&&span class=&o&&());&/span&
&span class=&k&&return&/span& &span class=&n&&md5&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Transactional&/span&
&span class=&cm&&/**&/span&
&span class=&cm&&
*使用注解控制事务方法的优点&/span&
&span class=&cm&&
* 1:开发团队达成一致约定,明确标注事务方法的编程风格&/span&
&span class=&cm&&
* 2:保证事务方法的执行时间尽可能短,不要穿插其他网络请求,RPC/HTTP请求或者剥离到事务方法外&/span&
&span class=&cm&&
* 3:不是所有的方法都需要事务,如只有一条修改操作,只读操作不需要事务控制&/span&
&span class=&cm&&
&span class=&kd&&public&/span& &span class=&n&&SeckillExecution&/span& &span class=&nf&&executeSeckill&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&,&/span& &span class=&kt&&long&/span& &span class=&n&&userPhone&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&md5&/span&&span class=&o&&)&/span& &span class=&kd&&throws&/span& &span class=&n&&SeckillException&/span&&span class=&o&&,&/span& &span class=&n&&RepeatKillException&/span&&span class=&o&&,&/span& &span class=&n&&SeckillCloseException&/span& &span class=&o&&{&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&md5&/span&&span class=&o&&==&/span&&span class=&kc&&null&/span& &span class=&o&&||!&/span&&span class=&n&&md5&/span&&span class=&o&&.&/span&&span class=&na&&equals&/span&&span class=&o&&(&/span&&span class=&n&&getMD5&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&))){&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&n&&SeckillException&/span&&span class=&o&&(&/span&&span class=&s&&&seckill data rewrite&&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&c1&&//执行秒杀逻辑:减库存+记录购买行为&/span&
&span class=&n&&Date&/span& &span class=&n&&nowTime&/span&&span class=&o&&=&/span&&span class=&k&&new&/span& &span class=&n&&Date&/span&&span class=&o&&();&/span&
&span class=&k&&try&/span& &span class=&o&&{&/span&
&span class=&c1&&//记录购买行为&/span&
&span class=&kt&&int&/span& &span class=&n&&insertCount&/span&&span class=&o&&=&/span&&span class=&n&&successKilledDao&/span&&span class=&o&&.&/span&&span class=&na&&insertSuccessKilled&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&userPhone&/span&&span class=&o&&);&/span&
&span class=&c1&&//唯一:seckillId,userphone&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&insertCount&/span&&span class=&o&&&=&/span&&span class=&mi&&0&/span&&span class=&o&&){&/span&
&span class=&c1&&//重复秒杀&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&n&&RepeatKillException&/span&&span class=&o&&(&/span&&span class=&s&&&seckill repeated&&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&&span class=&k&&else&/span&&span class=&o&&{&/span&
&span class=&c1&&//减库存,热点商品竞争&/span&
&span class=&kt&&int&/span& &span class=&n&&updateCount&/span&&span class=&o&&=&/span&&span class=&n&&seckillDao&/span&&span class=&o&&.&/span&&span class=&na&&reduceNumber&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&nowTime&/span&&span class=&o&&);&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&updateCount&/span&&span class=&o&&&=&/span&&span class=&mi&&0&/span&&span class=&o&&){&/span&
&span class=&c1&&//没有更新到记录,秒杀结束 rollback&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&n&&SeckillCloseException&/span&&span class=&o&&(&/span&&span class=&s&&&seckill is closed&&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&&span class=&k&&else&/span&&span class=&o&&{&/span&
&span class=&c1&&//秒杀成功 commit&/span&
&span class=&n&&SuccessKilled&/span& &span class=&n&&successKilled&/span&&span class=&o&&=&/span&&span class=&n&&successKilledDao&/span&&span class=&o&&.&/span&&span class=&na&&queryByIdWithSeckill&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&userPhone&/span&&span class=&o&&);&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&SeckillExecution&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span& &span class=&n&&SeckillStatEnum&/span&&span class=&o&&.&/span&&span class=&na&&SUCCESS&/span&&span class=&o&&,&/span&&span class=&n&&successKilled&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&&span class=&k&&catch&/span&&span class=&o&&(&/span&&span class=&n&&SeckillCloseException&/span& &span class=&n&&e1&/span&&span class=&o&&){&/span&
&span class=&k&&throw&/span& &span class=&n&&e1&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span& &span class=&k&&catch&/span& &span class=&o&&(&/span&&span class=&n&&RepeatKillException&/span& &span class=&n&&e2&/span&&span class=&o&&){&/span&
&span class=&k&&throw&/span& &span class=&n&&e2&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span& &span class=&k&&catch&/span& &span class=&o&&(&/span&&span class=&n&&Exception&/span& &span class=&n&&e&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&logger&/span&&span class=&o&&.&/span&&span class=&na&&error&/span&&span class=&o&&(&/span&&span class=&n&&e&/span&&span class=&o&&.&/span&&span class=&na&&getMessage&/span&&span class=&o&&(),&/span&&span class=&n&&e&/span&&span class=&o&&);&/span&
&span class=&c1&&//所有的编译期异常,转化为运行期异常(运行时异常,spring可以做rollback操作)&/span&
&span class=&k&&throw&/span& &span class=&k&&new&/span& &span class=&n&&SeckillException&/span&&span class=&o&&(&/span&&span class=&s&&&seckill inner error:&&/span&&span class=&o&&+&/span&&span class=&n&&e&/span&&span class=&o&&.&/span&&span class=&na&&getMessage&/span&&span class=&o&&());&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&span class=&c1&&//抛出异常是为了告诉spring是否rollback,此处使用存储过程的话,就不需要抛异常了&/span&
&span class=&kd&&public&/span& &span class=&n&&SeckillExecution&/span& &span class=&nf&&executeSeckillProcedure&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&,&/span& &span class=&kt&&long&/span& &span class=&n&&userPhone&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&md5&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&md5&/span& &span class=&o&&==&/span&&span class=&kc&&null&/span& &span class=&o&&||&/span& &span class=&o&&!&/span&&span class=&n&&md5&/span&&span class=&o&&.&/span&&span class=&na&&equals&/span&&span class=&o&&(&/span&&span class=&n&&getMD5&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&))){&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&SeckillExecution&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&SeckillStatEnum&/span&&span class=&o&&.&/span&&span class=&na&&DATA_REWRITE&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&n&&Date&/span& &span class=&n&&killTime&/span&&span class=&o&&=&/span&&span class=&k&&new&/span& &span class=&n&&Date&/span&&span class=&o&&();&/span&
&span class=&n&&Map&/span&&span class=&o&&&&/span&&span class=&n&&String&/span&&span class=&o&&,&/span&&span class=&n&&Object&/span&&span class=&o&&&&/span& &span class=&n&&map&/span&&span class=&o&&=&/span&&span class=&k&&new&/span& &span class=&n&&HashMap&/span&&span class=&o&&&&/span&&span class=&n&&String&/span&&span class=&o&&,&/span& &span class=&n&&Object&/span&&span class=&o&&&();&/span&
&span class=&n&&map&/span&&span class=&o&&.&/span&&span class=&na&&put&/span&&span class=&o&&(&/span&&span class=&s&&&seckillId&&/span&&span class=&o&&,&/span&&span class=&n&&seckillId&/span&&span class=&o&&);&/span&
&span class=&n&&map&/span&&span class=&o&&.&/span&&span class=&na&&put&/span&&span class=&o&&(&/span&&span class=&s&&&phone&&/span&&span class=&o&&,&/span&&span class=&n&&userPhone&/span&&span class=&o&&);&/span&
&span class=&n&&map&/span&&span class=&o&&.&/span&&span class=&na&&put&/span&&span class=&o&&(&/span&&span class=&s&&&killTime&&/span&&span class=&o&&,&/span&&span class=&n&&killTime&/span&&span class=&o&&);&/span&
&span class=&n&&map&/span&&span class=&o&&.&/span&&span class=&na&&put&/span&&span class=&o&&(&/span&&span class=&s&&&result&&/span&&span class=&o&&,&/span&&span class=&kc&&null&/span&&span class=&o&&);&/span&
&span class=&c1&&//执行存储过程,result被赋值&/span&
&span class=&k&&try&/span& &span class=&o&&{&/span&
&span class=&n&&seckillDao&/span&&span class=&o&&.&/span&&span class=&na&&killByProcedure&/span&&span class=&o&&(&/span&&span class=&n&&map&/span&&span class=&o&&);&/span&
&span class=&kt&&int&/span& &span class=&n&&result&/span&&span class=&o&&=(&/span&&span class=&n&&Integer&/span&&span class=&o&&)&/span& &span class=&n&&map&/span&&span class=&o&&.&/span&&span class=&na&&get&/span&&span class=&o&&(&/span&&span class=&s&&&result&&/span&&span class=&o&&);&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&result&/span&&span class=&o&&==&/span&&span class=&mi&&1&/span&&span class=&o&&){&/span&
&span class=&n&&SuccessKilled&/span& &span class=&n&&successKilled&/span&&span class=&o&&=&/span&&span class=&n&&successKilledDao&/span&&span class=&o&&.&/span&&span class=&na&&queryByIdWithSeckill&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&userPhone&/span&&span class=&o&&);&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&SeckillExecution&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span& &span class=&n&&SeckillStatEnum&/span&&span class=&o&&.&/span&&span class=&na&&SUCCESS&/span&&span class=&o&&,&/span&&span class=&n&&successKilled&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&&span class=&k&&else&/span&&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&SeckillExecution&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&SeckillStatEnum&/span&&span class=&o&&.&/span&&span class=&na&&stateof&/span&&span class=&o&&(&/span&&span class=&n&&result&/span&&span class=&o&&));&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span& &span class=&k&&catch&/span& &span class=&o&&(&/span&&span class=&n&&Exception&/span& &span class=&n&&e&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&logger&/span&&span class=&o&&.&/span&&span class=&na&&error&/span&&span class=&o&&(&/span&&span class=&n&&e&/span&&span class=&o&&.&/span&&span class=&na&&getMessage&/span&&span class=&o&&(),&/span&&span class=&n&&e&/span&&span class=&o&&);&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&SeckillExecution&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&,&/span&&span class=&n&&SeckillStatEnum&/span&&span class=&o&&.&/span&&span class=&na&&INNER_ERROE&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&h3&&b&三、Sping托管 service的实现类&/b&&/h3&&p&和上一篇文章使用spring托管dao接口一样,这里也需要用 spring 托管service. spring ioc 使用对象工程模式,对所有的注入的依赖进行了管理,暴露出了一致性的访问接口,当我们需要某个对象时,直接从spring ioc中取就行了,不需要new,也不需要对它们的生命周期进行管理。更为重要的是spring 自动组装依赖,比如最终的接口controller依赖service,而service依赖dao,dao依赖sessionfactory,而sessionfactory依赖datasource,这些层层依赖是通过spring管理并层层组装,只要我们简单配置和注解就可以方便的使用,代码的分层和编程的艺术在spring框架中展现得淋漓尽至。&/p&&blockquote&&p&本项目采用spring ioc :&/p&&p&1.xml配置&/p&&p&2.包扫描&/p&&p&3.annotation注解&/p&&/blockquote&&p&创建sping-service.xml&/p&&p&采用包扫描+注解方式,首先在xml中声明包扫描:&/p&&div class=&highlight&&&pre&&code class=&language-xml&&&span&&/span&&span class=&cp&&&?xml version=&1.0& encoding=&UTF-8&?&&/span&
&span class=&nt&&&beans&/span& &span class=&na&&xmlns=&/span&&span class=&s&&&http://www.springframework.org/schema/beans&&/span&
&span class=&na&&xmlns:xsi=&/span&&span class=&s&&&http://www.w3.org/2001/XMLSchema-instance&&/span&
&span class=&na&&xmlns:context=&/span&&span class=&s&&&http://www.springframework.org/schema/context&&/span& &span class=&na&&xmlns:tx=&/span&&span class=&s&&&http://www.springframework.org/schema/tx&&/span&
&span class=&na&&xsi:schemaLocation=&/span&&span class=&s&&&http://www.springframework.org/schema/beans&/span&
&span class=&s&&
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context&/span&
&span class=&s&&
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx&/span&
&span class=&s&&
http://www.springframework.org/schema/tx/spring-tx.xsd&&/span&
&span class=&nt&&&&/span&
&span class=&c&&&!--扫描service包下所有使用注解的类型--&&/span&
&span class=&nt&&&context:component-scan&/span& &span class=&na&&base-package=&/span&&span class=&s&&&org.forezp.service&&/span&&span class=&nt&&/&&/span&
&/code&&/pre&&/div&&p&然后在org,forezp.service包下的类采用注解。比如@Service 注解声明是一个service, @Autowired注入service 所需依赖。&br&&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Service&/span&&span class=&c1&&//声明是一个service&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&SeckillServiceImpl&/span& &span class=&kd&&implements&/span& &span class=&n&&SeckillService&/span&&span class=&o&&{&/span&
&span class=&c1&&//注入service依赖&/span&
&span class=&nd&&@Autowired&/span&
&span class=&kd&&private&/span& &span class=&n&&SeckillDao&/span& &span class=&n&&seckillDao&/span&&span class=&o&&;&/span&
&span class=&nd&&@Autowired&/span&
&span class=&kd&&private&/span& &span class=&n&&SuccessKilledDao&/span& &span class=&n&&successKilledDao&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&只需要一个包扫描和几个简单的注解就可以将service注解到spring
ioc容器中。&/p&&h3&&b&四、spring声明式事物&/b&&/h3&&p&在秒杀案例中,我们需要采用事物来防止数据的正确性,防止重复秒杀,防止库存不足、库存剩余等情况。一般使用事物需要开启事物/经常一些列的操作,提交或者回滚。spring声明式事物,就是将事物的开启、提交等托管给spring管理,我们只需要注重如何修改数据。&/p&&p&配置spring 声明式事物&br&在spring-service.xml中配置:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&o&&&!--&/span&&span class=&n&&配置事务管理器&/span&&span class=&o&&--&&/span&
&span class=&o&&&&/span&&span class=&n&&bean&/span& &span class=&n&&id&/span&&span class=&o&&=&/span&&span class=&s&&&transactionManager&&/span& &span class=&n&&class&/span&&span class=&o&&=&/span&&span class=&s&&&org.springframework.jdbc.datasource.DataSourceTransactionManager&&/span&&span class=&o&&&&/span&
&span class=&o&&&!--&/span&&span class=&n&&注入数据库连接池&/span&&span class=&o&&--&&/span&
&span class=&o&&&&/span&&span class=&n&&property&/span& &span class=&n&&name&/span&&span class=&o&&=&/span&&span class=&s&&&dataSource&&/span& &span class=&n&&ref&/span&&span class=&o&&=&/span&&span class=&s&&&dataSource&&/span&&span class=&o&&/&&/span&
&span class=&o&&&/&/span&&span class=&n&&bean&/span&&span class=&o&&&&/span&
&span class=&o&&&!--&/span&&span class=&n&&配置基于注解的声明式事务&/span&
&span class=&n&&默认使用注解来管理事务行为&/span&
&span class=&o&&--&&/span&
&span class=&o&&&&/span&&span class=&n&&tx&/span&&span class=&o&&:&/span&&span class=&n&&annotation&/span&&span class=&o&&-&/span&&span class=&n&&driven&/span& &span class=&n&&transaction&/span&&span class=&o&&-&/span&&span class=&n&&manager&/span&&span class=&o&&=&/span&&span class=&s&&&transactionManager&&/span&&span class=&o&&/&&/span&
&/code&&/pre&&/div&&p&在需要事物的业务逻辑下加 @Transactional注解。&br&比如在开启秒杀方法:&br&&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@Transactional&/span&
&span class=&kd&&public&/span& &span class=&n&&SeckillExecution&/span& &span class=&nf&&executeSeckill&/span&&span class=&o&&(&/span&&span class=&kt&&long&/span& &span class=&n&&seckillId&/span&&span class=&o&&,&/span& &span class=&kt&&long&/span& &span class=&n&&userPhone&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&md5&/span&&span class=&o&&)&/span& &span class=&kd&&throws&/span& &span class=&n&&SeckillException&/span&&span class=&o&&,&/span& &span class=&n&&RepeatKillException&/span&&span class=&o&&,&/span& &span class=&n&&SeckillCloseException&/span& &span class=&o&&{&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&md5&/span&&span class=&o&&==&/span&&span class=&kc&&null&/span& &span class=&o&&||!&/span&&span class=&n&&md5&/span&&span class=&o&&.&/span&&span class=&na&&equals&/span&&span class=&o&&(&/span&&span class=&n&&getMD5&/span&&span class=&o&&(&/span&&span class=&n&&seckillId&/span&&span class=&o&&))){&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&&em&&b&注意:&/b&&/em&&/p&&blockquote&&p&1开发团队达成一致约定,明确标注事务方法的编程风格&/p&&p&2:保证事务方法的执行时间尽可能短,不要穿插其他网络请求,RPC/HTTP请求或者剥离到事务方法外&/p&&p&3:不是所有的方法都需要事务,如只有一条修改操作,只读操作不需要事务控制&/p&&/blockquote&&h3&&b&五、单元测试&/b&&/h3&&p&需要配置:&/p&&blockquote&&p&@ContextConfiguration({&br&&classpath:spring/spring-dao.xml&,&br&&classpath:spring/spring-service.xml&&br&})&br&直接上代码:&/p&&/blockquote&&div class=&highlight&&&pre&&code class=&language-java&&&span&&/span&&span class=&nd&&@RunWith&/span&&span class=&o&&(&/span&&span class=&n&&SpringJUnit4ClassRunner&/span&&span class=&o&&.&/span&&span class=&na&&class&/span&&span class=&o&&)&/span&
&span class=&nd&&@ContextConfiguration&/span&&span class=&o&&({&/span&
&span class=&s&&&classpath:spring/spring-dao.xml&&/span&&span class=&o&&,&/span&
&span class=&s&&&classpath:spring/spring-service.xml&&/span&
&span class=&o&&})&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&SeckillServiceTest&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&kd&&final&/span& &span class=&n&&Logger&/span& &span class=&n&&logger&/span&&span class=&o&&=&/span&&span class=&n&&LoggerFactory&/span&&span class=&o&&.&/span&&span class=&na&&getLogger&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&getClass&/span&&span class=&o&&());&/span&
&span class=&nd&&@Autowired&/span&
&span class=&kd&&private&/span& &span class=&n&&SeckillService&/span& &span class=&n&&seckillService&/span&&span class=&o&&;&/span&
&span class=&nd&&@Test&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&getSerkillList&/span&&span class=&o&&()&/span& &span class=&kd&&throws&/span& &span class=&n&&Exception&/span& &span class=&o&&{&/span&
&span class=&n&&List&/span&&span class=&o&&&&/span&&span class=&n&&Seckill&/span&&span class=&o&&&&/span& &span class=&n&&list&/span&&span class=&o&&=&/span&&span class=&n&&seckillService&/span&&span class=&o&&.&/span&&span class=&na&&getSerkillList&/span&&span class=&o&&();&/span&
&span class=&n&&System&/span&&span class=&o&&.&/span&&span class=&na&&out&/span&&span class=&o&&.&/span&&span class=&na&&println&/span&&span class=&o&&(&/span&&span class=&n&&list&/span&&span class=&o&&);&/span&
&span class=&c1&&//执行结果[Seckill{seckillId=1000, name='1000元秒杀iphone6'..... 省略。。。]&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Test&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&getById&/span&&span class=&o&&()&/span& &span class=&kd&&throws&/span& &span class=&n&&Exception&/span& &span class=&o&&{&/span&
&span class=&kt&&long&/span& &span class=&n&&id&/span&&span class=&o&&=&/span&&span class=&mi&&1000&/span&&span class=&o&&;&/span&
&span class=&n&&Seckill&/span& &span class=&n&&seckill&/span&&span class=&o&&=&/span&&span class=&n&&seckillService&/span&&span class=&o&&.&/span&&span class=&na&&getById&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&);&/span&
&span class=&n&&System&/span&&span class=&o&&.&/span&&span class=&na&&out&/span&&span class=&o&&.&/span&&span class=&na&&println&/span&&span class=&o&&(&/span&&span class=&n&&seckill&/span&&span class=&o&&);&/span&
&span class=&c1&&//执行结果:Seckill{seckillId=1000, name='1000元秒杀iphone6', number=100, startTime=Sun Nov 01 00:00:00 CST 2015,。。。。}&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Test&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&exportSeckillUrl&/span&&span class=&o&&()&/span& &span class=&kd&&throws&/span& &span class=&n&&Exception&/span& &span class=&o&&{&/span&
&span class=&kt&&long&/span& &span class=&n&&id&/span&&span class=&o&&=&/span&&span class=&mi&&1000&/span&&span class=&o&&;&/span&
&span class=&n&&Exposer&/span& &span class=&n&&exposer&/span&&span class=&o&&=&/span&&span class=&n&&seckillService&/span&&span class=&o&&.&/span&&span class=&na&&exportSeckillUrl&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&);&/span&
&span class=&n&&System&/span&&span class=&o&&.&/span&&span class=&na&&out&/span&&span class=&o&&.&/span&&span class=&na&&println&/span&&span class=&o&&(&/span&&span class=&n&&exposer&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Test&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&executeSeckill&/span&&span class=&o&&()&/span& &span class=&kd&&throws&/span& &span class=&n&&Exception&/span& &span class=&o&&{&/span&
&span class=&kt&&long&/span& &span class=&n&&id&/span&&span class=&o&&=&/span&&span class=&mi&&1000&/span&&span class=&o&&;&/span&
&span class=&kt&&long&/span& &span class=&n&&phone&/span&&span class=&o&&=&/span&&span class=&mi&&L&/span&&span class=&o&&;&/span&
&span class=&n&&String&/span& &span class=&n&&md5&/span&&span class=&o&&=&/span&&span class=&s&&&e83eef2cc6b033ca0848878afc20e80d&&/span&&span class=&o&&;&/span&
&span class=&n&&SeckillExecution&/span& &span class=&n&&execution&/span&&span class=&o&&=&/span&&span class=&n&&seckillService&/span&&span class=&o&&.&/span&&span class=&na&&executeSeckill&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&,&/span&&span class=&n&&phone&/span&&span class=&o&&,&/span&&span class=&n&&md5&/span&&span class=&o&&);&/span&
&span class=&n&&System&/span&&span class=&o&&.&/span&&span class=&na&&out&/span&&span class=&o&&.&/span&&span class=&na&&println&/span&&span class=&o&&(&/span&&span class=&n&&execution&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&这篇文章主要讲了service业务接口的编写和实现,以及采用xml和注解方式讲service 注入到spring ioc,以及声明式事物,不得不感叹spring 的强大。下一篇文章讲讲述 web层的开发,spring mvc的相关配置。感谢大家,再接再厉。^_^&br&&/p&&p&上篇回顾:&/p&&p&&a href=&https://zhuanlan.zhihu.com/p/& class=&internal&&一篇SSM框架整合友好的文章(一)&/a&&/p&
来源:作者:方志朋讲述了DAO 层,mybatis实现数据库的连接,DAO层接口设计,以及mybtis和spring的整合。DAO层采用接口设计方式实现,接口和SQL实现的分离,方便维护。DAO层所负责的仅仅是接口的设计和实现,而负责的逻辑即一个…
建议不要硬着头皮看spring代码,本身的代码800多m,就是不上班开始看也不知道什么时候看完。如果想学学ioc,控制反转这些建议看看jodd项目,比较简练,但是我仍然不建议过多的看这些框架的代码,因为这些代码要完成任务需要很多琐碎的类实现,比如读取某个包下面的所有类,解析class的头文件,反射各种信息,再加上封装,很有可能在读源码的过程中掉到各种细节里出不来,所以读这种源码要事无巨细,理解原理即可。&br&基本原理其实就是通过反射解析类及其类的各种信息,包括构造器、方法及其参数,属性。然后将其封装成bean定义信息类、constructor信息类、method信息类、property信息类,最终放在一个map里,也就是所谓的container,池等等,其实就是个map。。汗。。。。当你写好配置文件,启动项目后,框架会先按照你的配置文件找到那个要scan的包,然后解析包里面的所有类,找到所有含有@bean,@service等注解的类,利用反射解析它们,包括解析构造器,方法,属性等等,然后封装成各种信息类放到一个map里。每当你需要一个bean的时候,框架就会从container找是不是有这个类的定义啊?如果找到则通过构造器new出来(这就是控制反转,不用你new,框架帮你new),再在这个类找是不是有要注入的属性或者方法,比如标有@autowired的属性,如果有则还是到container找对应的解析类,new出对象,并通过之前解析出来的信息类找到setter方法,然后用该方法注入对象(这就是依赖注入)。如果其中有一个类container里没找到,则抛出异常,比如常见的spring无法找到该类定义,无法wire的异常。还有就是嵌套bean则用了一下递归,container会放到servletcontext里面,每次reQuest从servletcontext找这个container即可,不用多次解析类定义。如果bean的scope是singleton,则会重用这个bean不再重新创建,将这个bean放到一个map里,每次用都先从这个map里面找。如果scope是session,则该bean会放到session里面。仅此而已,没必要花更多精力。建议还是多看看底层的知识。
建议不要硬着头皮看spring代码,本身的代码800多m,就是不上班开始看也不知道什么时候看完。如果想学学ioc,控制反转这些建议看看jodd项目,比较简练,但是我仍然不建议过多的看这些框架的代码,因为这些代码要完成任务需要很多琐碎的类实现,比如读取某个包…
&figure&&img src=&https://pic2.zhimg.com/v2-bbbb85c13f63debc5d270ea4_b.jpg& data-rawwidth=&1142& data-rawheight=&592& class=&origin_image zh-lightbox-thumb& width=&1142& data-original=&https://pic2.zhimg.com/v2-bbbb85c13f63debc5d270ea4_r.jpg&&&/figure&&h2&开发目标&/h2&&p&今天我们使用MyBatis和Spring MVC开发一个简单的问答网站,你可以使用Markdown来发布问题和答案。&/p&&p&这篇文章可以教会你以下知识:&/p&&ul&&li&MyBatis配置和使用最简单的姿势&/li&&li&MyBatis+Spring MVC实现一个简单的Web页面&/li&&li&MyBatis的核心类是干嘛用的(SqlSessionFactoryBuilder、SqlSessionFactory和SqlSession)&/li&&li&MyBatis-Spring如何使用,帮你做了哪些工作?&/li&&li&MyBatis Spring Boot Starter如何支持MyBatis,让你使用MyBatis的门槛降到最低&/li&&/ul&&p&相信看完本身是你开始使用MyBatis的一个非常棒的开始!&/p&&p&最终的效果图如下:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-6ea6f2ccd7c6db0b0e294_b.jpg& data-rawwidth=&1196& data-rawheight=&750& class=&origin_image zh-lightbox-thumb& width=&1196& data-original=&https://pic3.zhimg.com/v2-6ea6f2ccd7c6db0b0e294_r.jpg&&&/figure&&br&&br&&p&Web端的开发我们使用Spring MVC,对Spring MVC还不太熟悉的同学,可以看看天码营的&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/spring-mvc& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring MVC实战练习&/a&。当然,Spring MVC的部分不是这个练习的重点,也基本不影响大家的理解和练习。&/p&&p&这样一个系统麻雀虽小,五张俱全,会涉及MyBatis的很多核心知识。MyBatis确实是一个非常简单易学的ORM框架,很适合作为你学习的第一款Java ORM框架。&/p&&p&完整的教程请参考&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/spring-mvc-mybatis-qa& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《基于MyBatis和Spring MVC搭建问答网站》&/a&。网站Demo请见&a href=&https://link.zhihu.com/?target=http%3A//qa.app.tianmaying.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&MyBatis问答小网站&/a&。&br&&/p&&h2&ORM是什么?&/h2&&p&ORM是Object Relation Mapping的缩写,顾名思义,即对象关系映射。&/p&&p&ORM是一种以面向对象的方式来进行数据库操作的技术。Web开发中常用的语言,都会有对应的ORM框架。而MyBatis就是Java开发中一种常用ORM框架。&/p&&p&简单地理解,通过Java进行数据库访问的正常流程可以分为以下几步:&/p&&ol&&li&准备好SQL语句&/li&&li&调用JDBC的API传入SQL语句,设置参数&/li&&li&解析JDBC返回的结果&/li&&/ol&&p&这个过程实际上非常麻烦,比如:&/p&&ul&&li&在Java代码中拼接SQL非常麻烦,而且易于出错&/li&&li&JDBC的代码调用有很多重复性的代码&/li&&li&从JDBC返回的结果转换成领域模型的Java对象很繁琐&/li&&/ul&&p&而使用ORM框架,则可以让我们用面向对象的方式来操作数据库,比如通过一个简单的函数调用就完成上面整个流程,直接返回映射为Java对象的结果。这个流程中很大一部分工作其实交给ORM自动化地帮我们执行了。&/p&&h2&MyBatis简介&/h2&&p&MyBatis的入门知识最好的材料是其&a href=&https://link.zhihu.com/?target=http%3A//www.mybatis.org/mybatis-3/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&官方网站&/a&,而且其绝大部分内容都有中文版本。&/p&&p&官方网站上如下介绍MyBatis:&/p&&blockquote&&p&MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或标注,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。&/p&&/blockquote&&p&简单地理解,你可以认为MyBatis将SQL语句,以及SQL返回结果到Java对象的映射,都放到了一个易于配置的XML文件里了,你的Java代码就会变得异常简单。当然,除了XML,MyBatis同时也支持基于标注的方式,但是功能上会有一些限制。总体来说,我们推荐使用XML方式,一些简单的SQL使用标注会更方便一些。&/p&&h2&开发环境&/h2&&blockquote&&p&工欲善其事,必先利其器&/p&&/blockquote&&p&首先让我们搭建好本地的开发环境,这里不会事无巨细地描述环境中每一种工具的安装步骤和用法,你可以从参考材料以及Google中获取有用的信息。&/p&&h3&Java&/h3&&p&我们推荐安装&a href=&https://link.zhihu.com/?target=http%3A//www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JavaSE Development Kit 8&/a&。&/p&&p&参考&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/java-basic/lesson/java-environment& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Java开发环境安装与配置&/a&&/p&&h3&IDE&/h3&&p&IDE我们推荐使用&a href=&https://link.zhihu.com/?target=http%3A//www.eclipse.org/home/index.php& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Eclipse&/a&或&a href=&https://link.zhihu.com/?target=https%3A//www.jetbrains.com/idea/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&IntelliJ IDEA&/a&(当然还有很多别的选择),它们对Maven项目的支持非常完善,自动提示、补全功能异常强大,对于开发效率的提升非常明显。&/p&&p&参考&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/java-basic/lesson/eclipse%230& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Eclipse安装和使用&/a&&/p&&h3&Maven&/h3&&p&Maven是Java世界中最流行的项目构建工具,理论上来说在安装了IDE后,IDE内部会自带一个Maven的安装版本,如果想在命令行工具中使用Maven命令,可以单独进行安装。&/p&&p&参考:&/p&&ul&&li&&a href=&https://link.zhihu.com/?target=http%3A//www.tianmaying.com/tutorial/maven-basic& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Maven基本概念&/a&&/li&&li&&a href=&https://link.zhihu.com/?target=http%3A//www.tianmaying.com/tutorial/maven-demo& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&如何通过Maven构建项目&/a&&/li&&li&&a href=&https://link.zhihu.com/?target=http%3A//www.tianmaying.com/tutorial/maven-project-management& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&通过Maven进行项目构建与管理&/a&&/li&&/ul&&p&如果想深入了解,推荐&a href=&https://link.zhihu.com/?target=https%3A//book.douban.com/subject/5345682/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Maven实战&/a&。&/p&&h3&H2&/h3&&p&我们使用内嵌的数据库H2,如果希望转换成其他数据库,比如MySQL,只需修改数据库连接串即可。当然别忘了要在依赖中增加相应的数据库访问驱动包。H2数据库不需要你任何额外的安装工作。&/p&&h2&创建项目&/h2&&p&接下来我们开始创建第一个MyBatis项目吧。新建一个Maven项目,项目结构如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&.
├── pom.xml
├── src
├── main
└── java
└── com
└── tianmaying
&/code&&/pre&&/div&&p&接下来引入MyBatis和H2的依赖:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&dependency&
&groupId&org.mybatis&/groupId&
&artifactId&mybatis&/artifactId&
&version&3.4.0&/version&
&/dependency&
&dependency&
&groupId&com.h2database&/groupId&
&artifactId&h2&/artifactId&
&version&1.4.192&/version&
&scope&runtime&/scope&
&/dependency&
&/code&&/pre&&/div&&p&既然是ORM的练习,那么我们先设计Object,在设计Relation,最后来来看怎么做Mapping。&/p&&h2&领域类设计&/h2&&p&关于领域类设计,&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/java-snake%2Boverview& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&贪吃蛇的游戏的练习&/a&中有一个简单讲解,请参考&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/java-snake%2Boverview& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&如何开始面向对象设计&/a&。&/p&&p&分析我们的业务场景,可以设计三个类:&/p&&ul&&li&Question表示问题&/li&&li&Answer表示回答&/li&&li&Tag表示问题标签&/li&&/ul&&p&其中:&/p&&ul&&li&Question可以有多个Answer,一个Answer对应唯一一个Question,一对多的关系&/li&&li&Question可以有多个Tage,一个Tag可用于多个Question,多对多的关系&/li&&/ul&&p&这三个类的关系用UML图如下:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-3c329bf8d04fa413ad21_b.jpg& data-rawwidth=&585& data-rawheight=&159& class=&origin_image zh-lightbox-thumb& width=&585& data-original=&https://pic3.zhimg.com/v2-3c329bf8d04fa413ad21_r.jpg&&&/figure&&br&&br&&p&UML中用菱形+横线的方式,表示包含关系。同样是包含,大家注意左侧的菱形是填充的,而右侧没有填充,这两者的区别在于:&/p&&ul&&li&Question消失时,Answer必然也消失了,它们有相同的生命周期,皮之不存,毛将焉附嘛&/li&&li&Question消失时,Tag则可以仍然存在,因为Tag还可以标注其他问题&/li&&/ul&&p&现在我们暂时不管Answer和Tag,只关注Question,先从最简单的单表情况开始学习。Question的代码如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public class Question implements Serializable {
private Date createdT
private List&Tag&
private List&Answer&
&/code&&/pre&&/div&&p&这里Question实现了Serializable接口,在这一节的练习中不是必须的。实现这个接口是为了后面缓存查询结果是需要。&/p&&h2&数据库设计&/h2&&p&除了设计用于Question,Answer和Tag数据的表,我们还需要定义一张维护Question和Tag之间多对多关系的表。最终数据库设计如下:&/p&&figure&&img src=&https://pic6.zhimg.com/v2-89c8feb6edf3af26aad0728_b.jpg& data-rawwidth=&667& data-rawheight=&339& class=&origin_image zh-lightbox-thumb& width=&667& data-original=&https://pic6.zhimg.com/v2-89c8feb6edf3af26aad0728_r.jpg&&&/figure&&br&&br&&p&这个阶段你只需关注question表即可。&/p&&h2&添加MyBatis的配置&/h2&&p&接下来我们添加MyBatis配置,在resources目录下建立mybatis.xml文件:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&?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&
&property name=&url& value=&jdbc:h2:mem:dataSINIT=RUNSCRIPT FROM 'classpath:database/schema.sql'\;RUNSCRIPT FROM 'classpath:database/data.sql'& /&
&/properties&
&environments default=&development&&
&environment id=&development&&
&transactionManager type=&JDBC&/&
&dataSource type=&POOLED&&
&property name=&driver& value=&org.h2.Driver&/&
&property name=&url& value=&${url}&/&
&/dataSource&
&/environment&
&/environments&
&mapper resource=&com/tianmaying/qa/mapper/QuestionMapper.xml&/&
&/mappers&
&/configuration&
&/code&&/pre&&/div&&p&这就是一个最简单的MyBatis配置文件,定义了数据源和mapper文件的位置。&/p&&p&注意H2的连接串中执行了创建数据库表和插入初始化数据的脚本,天码营已经为你准备了一些数据。&/p&&h3&关于MyBatis配置&/h3&&p&关于MyBatis本身的配置请参加&a href=&https://link.zhihu.com/?target=http%3A//www.mybatis.org/mybatis-3/zh/configuration.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&官方文档的介绍&/a&。&/p&&p&后面你会发现有了Spring和Spring Boot支持,很多配置不需要我们手动设置了,比如映射文件位置、数据源和事务管理器等。这个文件需要的内容非常少,甚至可以不需要这个文件了。&/p&&p&需要修改MyBatis配置文件的几种常见情况包括:&/p&&ul&&li&要增加插件(比如后面我们看到的分页插件)&/li&&li&修改MyBatis的运行时行为,参考settings的选项&/li&&li&重写类型处理器或创建自定义的类型处理器来处理非标准的类型,天码营的这个练习中不会涉及&/li&&/ul&&p&&mapper resource=&com/tianmaying/qa/mapper/QuestionMapper.xml&/&中表示com/tianmaying/qa/mapper/目录下的QuestionMapper.xml是定义对象关系映射的XML文件,马上就能看到它长什么样子。&/p&&h2&定义Mapper接口&/h2&&p&先来定义Mapper的Java接口,这是我们数据库访问的接口:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&package com.tianmaying.qa.
import com.tianmaying.qa.model.Q
import org.apache.ibatis.annotations.P
public interface QuestionMapper {
Question findOne(@Param(&id&) Long id);
&/code&&/pre&&/div&&p&@Param是MyBatis提高的一个标注,表示id会解析成SQL语句(SQL语句会在XML配置或者标注中)的参数。&/p&&h2&使用XML定义Mapper&/h2&&p&对应于Mapper接口,还需要通过XML来给出Mapper的实现。我们将映射文件一般放在resources目录下的com/tianmaying/qa/mapper/子目录(这是一个四层目录,与Mapper的包名一致)。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&?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.tianmaying.qa.mapper.QuestionMapper&&
&select id=&findOne& resultType=&com.tianmaying.qa.model.Question&&
SELECT * FROM question WHERE question.id = #{id}
&/code&&/pre&&/div&&p&Mapper的配置是MyBatis的精华,我们暂时不做详解。这里你注意两点即可:&/p&&ul&&li&对应于每一个Mapper的Java接口方法,XML配置中有对应的一个元素来描述其SQL语句&/li&&li&resultMap元素定义了数据库返回(一行记录)如何映射到一个Java对象&/li&&/ul&&h2&使用Mapper&/h2&&p&已经有了一个可以根据id获取问题的接口方法,接下来就可以进行调用了:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public static void main(String[] args) {
// 准备工作
InputStream inputStream =
// CONFIG_LOCATION的值即为MyBatis配置文件的路径
inputStream = Resources.getResourceAsStream(CONFIG_LOCATION);
} catch (IOException e) {
e.printStackTrace();
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取mapper
QuestionMapper questionMapper = sqlSession.getMapper(QuestionMapper.class);
// 调用mapper方法
Question question = questionMapper.findOne((long) 1);
System.out.println(question);
} finally {
// 最后一定关闭SqlSession
sqlSession.close();
&/code&&/pre&&/div&&p&把这个Main方法Run起来你就能看到结果了。调用看起来有点复杂,这里涉及MyBatis的几个关键类:&/p&&ul&&li&SqlSessionFactoryBuilder&/li&&li&SqlSessionFactory&/li&&li&SqlSession&/li&&/ul&&p&其实后面我们会引入Spring Boot,你会发现这几个类都被屏蔽掉了,你只需专注于写Mapper即可。不过了解一下这几个类,对于我们调试程序和理解MyBatis都是大有裨益的。&/p&&h2&引入Spring Boot&/h2&&p&上一个练习我们了解了MyBatis的基本用法,但是一个控制台应用显然不够酷,我们接下来就开始在Web应用中来使用MyBatis吧。&/p&&p&首先我们引入Spring Boot,为项目的POM文件添加一个父POM,在POM文件中的project根元素中添加:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&parent&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter-parent&/artifactId&
&version&1.4.1.RELEASE&/version&
&relativePath/&
&/code&&/pre&&/div&&p&然后添加以下依赖:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-devtools&/artifactId&
&/dependency&
&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter-thymeleaf&/artifactId&
&/dependency&
&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter-web&/artifactId&
&/dependency&
&dependency&
&groupId&net.sourceforge.nekohtml&/groupId&
&artifactId&nekohtml&/artifactId&
&/dependency&
&/code&&/pre&&/div&&p&关于Spring Boot请参考以下资料:&/p&&ul&&li&&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/spring-mvc%2Bstart%233& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&如何创建Spring Boot项目&/a&&/li&&li&&a href=&https://link.zhihu.com/?target=https%3A//www.tianmaying.com/tutorial/spring-boot-overview& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring Boot——开发新一代Spring Java应用&/a&&/li&&/ul&&h2&编写Controller和页面&/h2&&p&我们使用Spring MVC和Thymeleaf来实现前端页面。&/p&&p&这里有一个非常适合新手看得&a href=&https://link.zhihu.com/?target=https%3A//www.tianmaying.com/tutorial/spring-mvc-quickstart& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring MVC的快速入门&/a&。更深入地学习Spring MVC请参考&a href=&https://link.zhihu.com/?target=https%3A//course.tianmaying.com/spring-mvc%2Bstart& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring MVC实战练习&/a&。&/p&&p&这里我们先写出Controller的代码骨架:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&@Controller
public class QuestionController {
@GetMapping(&/{id}&)
public String showQuestion(@PathVariable Long id, Model model) {
// 1. 获取Mapper
// 2. 调用Mapper方法获取Question
// 3. 填充用以渲染页面的模型,这里即是Question实例
model.addAttribute(&question&, question);
// 返回模板名称
return &question&;
&/code&&/pre&&/div&&p&Thymeleaf的页面细节这里不再详述。我们把上节练习中main函数的代码放到Controller中来就基本完成一个Web页面的开发了。&/p&&p&不过这里我们可以做一些优化,而不是简单把代码搬过来用。优化的过程中来进一步理解MyBatis的几个核心类。这几个核心类的讨论你可以参考&a href=&https://link.zhihu.com/?target=http%3A//www.mybatis.org/mybatis-3/zh/getting-started.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&官方文档&/a&。&/p&&h2&SqlSessionFactory和SelSessionFactoryBuilder&/h2&&h3&SqlSessionFactoryBuilder&/h3&&p&SqlSessionFactoryBuilder这个类是用来创建SqlSessionFactory的,一旦创建了SqlSessionFactory实例,就不再需要它了。因此SqlSessionFactoryBuilder 实例的最佳范围是方法范围(也就是局部方法变量)。可以重用SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好不要让其一直存在,比如通过一个类的成员去引用是不推荐的。&/p&&h3&SqlSessionFactory&/h3&&p&SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次,多次重建SqlSessionFactory被视为一种代码“坏味道(bad smell)”。因此SqlSessionFactory的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。&/p&&h3&通过单例创建SqlSessionFactory&/h3&&p&可见,SqlSessionFactoryBuilder应该用完即扔,而SqlSessionFactory应该只创建一次且在整个应用内存在。因此我们这里使用单例模式来获得SqlSessionFactory实例。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&package com.tianmaying.qa.
import org.apache.ibatis.io.R
import org.apache.ibatis.session.SqlSessionF
import org.apache.ibatis.session.SqlSessionFactoryB
import java.io.IOE
import java.io.InputS
public class SqlSessionFactoryManager {
private static final String CONFIG_LOCATION = &mybatis.xml&;
private static SqlSessionFactory sqlSessionF
// 静态单例模式
public static SqlSessionFactory getSqlSessionFactory() {
if (sqlSessionFactory == null) {
InputStream inputStream =
inputStream = Resources.getResourceAsStream(CONFIG_LOCATION);
} catch (IOException e) {
e.printStackTrace();
// ** SqlSessionFactoryBuilder用完即扔
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionF
&/code&&/pre&&/div&&p&基于这样一个辅助类,获取应用的SqlSessionFactory实例可以如下方式:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&SqlSessionFactory sqlSessionFactory = SqlSessionFactoryManager.getSqlSessionFactory();
&/code&&/pre&&/div&&h2&SqlSession&/h2&&p&SqlSession实例不是线程安全的,因此是不能被共享的,所以它的最佳的范围是请求或方法范围。不能将SqlSession实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也不能将SqlSession实例的引用放在任何类型的管理范围中,比如Serlvet中的HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的范围中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。下面的示例就是一个确保 SqlSession 关闭的标准模式:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&SqlSession session = sqlSessionFactory.openSession();
// do work
} finally {
session.close();
&/code&&/pre&&/div&&p&了解了以上三个类之后,Controller最终的代码实现为:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&@Controller
public class QuestionController {
@GetMapping(&/{id}&)
public String showQuestion(@PathVariable Long id, Model model) {
SqlSession sqlSession = SqlSessionFactoryManager.getSqlSessionFactory().openSession();
QuestionMapper questionMapper = sqlSession.getMapper(QuestionMapper.class);
model.addAttribute(&question&, questionMapper.findOne(id));
return &question&;
} finally {
sqlSession.close();
&/code&&/pre&&/div&&h2&启动Spring Boot应用&/h2&&p&修改MybatisQaApplication的代码,使之成为一个Spring Boot应用:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&@SpringBootApplication
@Controller
public class MybatisQaApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisQaApplication.class, args);
&/code&&/pre&&/div&&p&在resources目录下增加一个应用配置文件application.properties,内容为:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&spring.thymeleaf.mode=LEGACYHTML5
&/code&&/pre&&/div&&p&这一行配置是为了让Thymeleaf支持HTML5。&/p&&p&此时你在命令行或者IDE中运行mvn spring-boot:run就可以启动应用,访问http:localhost:8080/1这样的URL就能获取id为1的问题的详细信息了。&/p&&h2&什么是MyBatis-Spring&/h2&&p&MyBatis官方文档中这样介绍&a href=&https://link.zhihu.com/?target=http%3A//www.mybatis.org/spring/zh/index.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&MyBatis-Spring&/a&:&/p&&blockquote&&p&MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。 使用这个类库中的类, Spring 将会加载必要的 MyBatis 工厂类和 session 类。 这个类库也提供一个简单的方式来注入 MyBatis 数据映射器和 SqlSession 到业务层的 bean 中。 而且它也会处理事务, 翻译 MyBatis 的异常到 Spring 的 DataAccessException 异常(数据访问异常,译者注)中。最终,它不会依赖于 MyBatis,Spring 或 MyBatis-Spring 来构建应用程序代码。&/p&&/blockquote&&p&总之MyBatis-Spring帮我们做了很多事情,最核心的有两点:&/p&&ul&&li&&p&Spring 将会加载必要的 MyBatis 工厂类和 session 类:这意味着不需要我们自己去创建SqlSessionFactory实例和SqlSession实例了,帮我们从MyBatis底层API中解放出来啦&/p&&/li&&li&&p&提供一个简单的方式来注入 MyBatis 数据映射器和 SqlSession 到业务层的 bean 中:使用Spring当然要使用依赖注入了,不需要我们自己手动创建Mapper了,直接注入即可&/p&&/li&&/ul&&p&如何理解下面这句话呢?&/p&&blockquote&&p&最终,它不会依赖于 MyBatis,Spring 或 MyBatis-Spring 来构建应用程序代码。&/p&&/blockquote&&p&正因为MyBatis-Spring帮我们做了这些事,我们的业务代码就可以完全屏蔽MyBatis的API了,对应于Controller的代码,直观上理解就是你将不会看到关于MyBatis相关类的import了。&/p&&p&来看实例吧。&/p&&h2&引入MyBatis-Spring&/h2&&p&要使用MyBatis-Spring模块,只需在POM文件中引入必要的依赖即可,这里我们引入1.3.0版本:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&dependency&
&groupId&org.mybatis&/groupId&
&artifactId&mybatis-spring&/artifactId&
&version&1.3.0&/version&
&/dependency&
&/code&&/pre&&/div&&h2&XML配置&/h2&&p&MyBatis-Spring引入了SqlSessionFactoryBean来创建SqlSessionFactory,这是一个工厂Bean,在XML中如下配置:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&bean id=&sqlSessionFactory& cl}

我要回帖

更多关于 提示 英文 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信