目录
1.事务(Transaction)
事务是数据库中的可以保证多个(至少2个)写操作(增、删、改)要么全部执行成功,要么全部执行失败的机制!
在基于Spring JDBC的项目中,使用@Transactional
注解,即可使得注解的方法是事务性的。
关于@Transactional
注解,可以添加在:
- 接口上
- 等效于在每个抽象方法上添加了此注解
- 接口的抽象方法上
- 仅作用于当前方法(重写的方法运行时)
- 实现类上
- 等效于在每个重写的接口的方法上添加了此注解
- 实现类中重写的接口的方法上
- 仅作用于当前方法
提示:此注解可以配置一些参数,如果同时在接口/类、接口的抽象方法/类重写的方法上添加此注解并配置了不同的参数值,则以方法上的配置为准。
注意:Spring JDBC是基于接口的代理模式来实现事务管理的!所以,如果在实现类中的自定义方法上添加@Transactional
注解是错误的做法!仅当对应的方法是在业务接口中已经声明的,使用@Transactional
才是正确的!
关于事务处理过程中的几个概念:
- 开启事务:BEGIN
- 提交事务:COMMIT
- 回滚事务:ROLLBACK
在Spring JDBC的事务管理中,大致是:
开启事务
try {
执行你的业务方法
提交事务
} catch (RuntimeException e) {
回滚事务
}
可以看到,Spring JDBC的事务管理中,默认将根据RuntimeException
进行回滚,可以通过@Transactional
注解的rollbackFor
/ rollbackForClassName
这2个属性中的某1个进行修改,设置为对特定的异常进行回滚,还可以配置noRollbackFor
/ noRollbackForClassName
这2个属性,设置对特定的异常不回滚。
【小结】关于事务:
- 如果某个业务方法涉及超过1次的增、删、改操作,需要保证此业务方法是事务性的;
- 推荐在业务的抽象方法上添加
@Transactional
注解即可保证此业务方法是事务性- 对于初学者,更推荐在业务接口上添加
@Transactional
,则此接口中所有抽象方法都是事务性,可能其中的某些抽象方法并不需要是事务性的,但是,这种做法比较稳妥,能避免遗漏导致的错误
- 对于初学者,更推荐在业务接口上添加
- 为了保证事务能够按照预期进行回滚,需要:
- 业务层必须由接口和实现类组成
- Spring JDBC是基于接口代理模式实现事务管理的,如果没有接口,则无法实现
- 所有增、删、改操作完成后,应该及时获取返回结果,并对结果进行判断,如果结果不符合预期,应该抛出异常,且异常应该是
RuntimeException
或其子孙类异常- Spring JDBC在管理事务时,默认按照
RuntimeException
进行回滚
- Spring JDBC在管理事务时,默认按照
- 业务层必须由接口和实现类组成
2. 关于@RequestMapping
注解
在Spring MVC框架中,@RequestMapping
注解的主要作用是:绑定“请求路径”与“处理请求的方法”的映射关系。
关于此注解的声明的源代码:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
}
以上源代码中的@Target({ElementType.TYPE, ElementType.METHOD})
就表示了此注解可以添加在哪里,其中,ElementType.TYPE
表示可以添加在“类型”上,ElementType.METHOD
表示可以添加在方法上。
在控制器类上,添加@RequestMapping
配置的路径值,将作为当前控制器类中每个处理请求的路径的前缀部分!例如在类上配置为@RequestMapping("/brands")
,在方法上配置为@RequestMapping("/delete")
,则完整路径为/brands/delete
,并且,此控制器类中所有处理请求的方法的路径上都有/brands
前缀!
所以,强烈推荐在每个控制器类上都使用@RequestMapping
配置路径的前缀部分。
关于注解内部的源代码,以@RequestMapping
为例,其内部有:
String name() default "";
以上源代码中,name()
表示此注解有名为name
的属性,左侧的String
表示此属性的数据类型,右侧的default ""
表示此属性的默认值。例如:可以在@RequestMapping
中配置名为name
的属性:
@RequestMapping(name = "test")
在@RequestMapping
中,还有:
@AliasFor("path")
String[] value() default {};
则以上源代码表示:此注解中有名为value
的属性,值是String[]
类型的,则默认值是空数组。
在Java语言中,注解的value
属性是默认的属性,如果注解只需要配置这1个属性的值,则可以不必显式的声明属性名称,例如:
@RequestMapping(value = {"value1", "value2", "value3"})
@RequestMapping({"value1", "value2", "value3"})
以上2种配置是完全等效的!
在Java语言中,如果某个属性的值是某种数组类型,但是,配置的数组值只有1个元素,则不必使用大括号将其框住,例如:
@RequestMapping(value = {"value1"})
@RequestMapping(value = "value1")
以上2种配置是完全等效的!
关于源代码中value
属性的声明,还添加了@AliasFor("path")
,表示此value
属性等效于当前注解中的path
属性!
在@RequestMapping
注解的源代码中,还有:
RequestMethod[] method() default {};
以上注解的作用是“限制请求方式”,在没有配置此属性的情况,任何请求方式都是允许的!例如:
@RequestMapping(value = "/add-new", method = RequestMethod.POST)
如果使用以上配置,则/add-new
路径只允许通过POST
方式提交请求,如果使用其它请求方式,将出现405
错误!
强制推荐将所有请求都限制请求方式!
在Spring MVC框架中,还定义了相关注解,以简化限制请求方式的配置:
@GetMapping
@PostMapping
PutMapping
DeleteMapping
PatchMapping
以上这些都相当于是限制了请求方式的@RequestMapping
!
小结:
- 推荐在每个控制器类上使用
@RequestMapping
配置请求路径前缀 - 推荐在每个处理请求的方法上使用
@GetMapping
/@PostMapping
配置请求路径