0 前言
一个基于SSM框架的高并发秒杀系统采用IDEA+Maven+SSM+Mysql+Redis+Jetty、Bootstrap/Jquery开发。
通过这个小项目,理清了基于SSM框架开发Web应用的流程以及常见的避坑方法,并在最后简单采用了Redis缓存以及Mysql Procedure对项目进行了高并发优化。
接下来从DAO层、Service层、Web层开发以及高并发优化4个方面梳理整个项目开发过程。
源码地址https://github.com/Allegr0/seckill
项目准备;
新建工程,用maven组织框架,从archtype:webapp中新建,在pom.xml添加相关依赖。修改默认web.xml中的servlet支持版本为3.1,在pom.xml添加项目所需依赖,并添加jetty服务器插件
1 DAO层相关开发
1.1 数据库设计与编码
数据库DDL在main/sql/schema.sql,这里采用纯手写DDL的方式创建数据库,这样的良好习惯相当于对每次数据库的改动都留下记录,方便了项目后期维护。
1.2 DAO实体与接口编码
分别放在org/seckill/entity目录下和org/seckill/dao目录下。 数据库中的Table <--> JavaPOJO类 Entity 是一对一的关系,数据库表对应实体类,数据库表中的列对应实体类的属性。
由于我们采用Mybatis ORM框架,所以这里dao目录下只存放接口以及抽象方法,描述功能,具体的SQL在Mybatis的Mapper中实现。
1.3 基于Mybatis实现DAO
Mybatis相当于其他ORM框架的优点:采用XML提供SQL,提供了足够的灵活性,Mapper自动实现DAO接口方法,并将结果自动集映射到javaPOJO。
配置resources/mybatis-config.xml配置文件。一些mybatis特性的全局属性(使用列别名替换列名、驼峰命名转换)可以自动的把sql中的下划线命名形式转为java中的驼峰命名形式,例如:create_time (sql)<—> createTime (java)。
在resources/mapper目录下写xml(sql语句),对应DAO中接口定义的所有抽象方法 tips:(注意Xml标签转义字符 <![CDATA[ <= ]]>、联合主键的使用、insert ignore技巧)
1.4 基于Spring托管Mybatissqlsessfactory对象
在resources/spring 目录下编写spring-dao.xml的配置文件(注意这里jdbc.properties 最好用jdbc.username不能直接用username,否则会报错),向Spring IOC中装配dao层所需要的bean,包括数据库连接池、mybatis很关键的sqlsessionfactory对象,以及扫描DAO接口实现类并注入进IOC。
1.5 DAO层单元测试
用command+shift+T 生成junit单元测试类,并测试。 tips:bean的自动注入用两种方法@Resource、@Autowired 。一个是按名称、一个是按类型。
单元测试的时候有一个小坑: 异常:org.apache.ibatis.binding.BindingException。由于 DAO接口参数 -> XML SQL参数绑定的时候,由于java没有保存形参的记录。queryAll(int offset, int limit) —> querryAll(arg0, arg1),当有多个参数的时候会出现找不到参数的问题。 所以在DAO层的接口函数参数前要标注@param(“参数名") 例如:queryAll(@Param("offset") int offset, @Param("limit") int limit);
1.6 总结
由于采用了MybatisORM框架,DAO层工作演变为:接口设计+SQL编写。代码和SQL分离,方便后期review。
DAO层只实现相关数据库的增删改查基本功能,具体的DAO拼接等复杂逻辑在Service层完成。
2 Service层相关开发
2.1 准备工作:新建dto、exception、service三个package
dto:数据传输层,存放一些表示数据的类型。dto和entity较像,entity是业务(数据库Table)的封装,dto是关注web和service之间的数据传递,dto层还包括了json格式的封装类。
spring声明式事务只接收RuntimeException(运行期异常),只对运行期异常进行回滚。
2.2 秒杀Service接口设计(站在“使用者”的角度设计)
service/SeckillService.java 秒杀接口包含4个方法:查询全部秒杀记录、查询单个秒杀记录、暴露秒杀地址、执行秒杀。配合接口中的方法,要同时设计好dto类以及异常类。
2.3 秒杀Service接口实现
service/impl/SeckillServiceImpl.java 。新建枚举类enums/SeckillStateEnum 存放状态,状态信息对应的常量。
在IntelliJ idea 2017.2 中@Resourse 或者 @Autowired出现警告或者错误提示(Could not autowire. no beans of "XXX" type found.). 但是程序运行无误。可以在IDEA中配置降低此类问题的警告级别。
2.4 基于Spring托管Service实现类
在resources/spring 目录下编写spring-service配置文件,以便向IOC装配service层的bean。通过
<!--扫描service包下所有使用注解的类型--> <context:component-scan base-package="org.seckill.service"/>
扫描类包,将所有标注Spring注解的@Component、@Service、@Controller、@Respository的类自动转换为bean并注入到IOC容器中,同时对代码中标注了@Autowired、@Resource的方法或成员变量根据名称或类型进行依赖注入。
2.5 使用Spring声明式事务
Spring声明式事务有两种常见的用法:1) tx:advice+aop命名空间,一次配置永久生效。2) @Transcational,通过注解标注需要事务的方法。
不是所有方法都需要事务,如只有一条修改操作、只读操作不要事务控制,所以这里建议用注解控制(@Transcational)的方式标注需要事务的方法,而不建议采用tx-advice+aop命名空间对所有方法都标注事务。个人理解:当有两条以上的修改操作或select for update,才需要事务,这个还需要进一步学习mysql行级锁。
标注了@Transcational方法,开启一个事务,再最后return或者throw RuntimeException时才commit或rollback
在spring-service.xml配置事务管理器,配置基于注解的声明式事务。
2.6 集成测试
slf4j接口的实现类logback配置:resources/logback.xml。在需要使用的测试类前声明logger变量
private final Logger logger = LoggerFactory.getLogger(this.getClass());
3 Web层相关开发
3.1 Restful接口与SpringMVC概述
REST是英文representational state transfer(表象性状态转变)或者表述性状态转移;Rest是web服务的一种架构风格;使用HTTP,URI,XML,JSON,HTML等广泛流行的标准和协议;轻量级,跨平台,跨语言的架构设计;它是一种设计风格,不是一种标准,是一种思想。
Restful架构:(1) 每一个URI代表一种资源。(2) 客户端和服务器之间,传递这种资源的某种表现层;(3) 客户端通过四个HTTP动词,队伍段资源进行操作,实现“表现层状态转化”。
由于篇幅原因,在这里就不对Restful接口进行详细介绍
Spring MVC框架原理
原文地址:https://www.cnblogs.com/kukri/p/9027813.html