【SSM项目】尚筹网(二)基于Servlet3.0项目搭建:日志系统以及声明式事务
1 日志系统
常见的日志系统实现log4j、JUL(jdk自带)、log4j2、logback(和SLF4J同一个作者,能够天然衔接),这些实现就类似于java的接口实现,而SLF4J就类似于java的接口。如下图是slf4j对不同日志系统接口实现的整合。
1.1 导入依赖
<!-- 日志 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
1.2 主动打印日志
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {RootConfig.class})
public class CrowdTest {
@Test
public void test() throws SQLException {
// 1 获取logger对象,传入的class对象就是当前打印日志的类
Logger logger = LoggerFactory.getLogger(CrowdTest.class);
// 2 根据当前的日志级别打印日志
logger.debug("123");
}
}
17:48:31.771 [main] DEBUG com.hikaru.crowd.CrowdTest - 123
1.3 替换Spring的JCL
Spring5可以省略这一步,因为发现slf4j后会自动进行替换,这时候直接导入依赖使用logback就可以。
1.4 logback配置文件
想要控制日志格式以及级别需要进行配置logback.xml.
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 指定日志输出的位置 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 日志输出的格式 -->
<!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体
内容、换行 -->
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n
</pattern>
</encoder>
</appender>
<!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
<!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
<root level="INFO">
<!-- 指定打印日志的 appender,这里通过“STDOUT”引用了前面配置的 appender -->
<appender-ref ref="STDOUT"/>
</root>
<!-- 根据特殊需求指定局部日志级别 -->
<logger name="com.hikaru.crowd.mapper" level="DEBUG"/>
</configuration>
一般情况下是全局指定INFO级别,然后根据特殊需求指定局部日志级别
如这里就是对mapper使用了DEBUG级别,则会打印出mapper接口方法执行的SQL
[18:14:51.257] [DEBUG] [main] [com.hikaru.crowd.mapper.UserMapper.getMaxId] [==> Preparing: select MAX(id) from t_user]
[18:14:51.289] [DEBUG] [main] [com.hikaru.crowd.mapper.UserMapper.getMaxId] [==> Parameters: ]
[18:14:51.313] [DEBUG] [main] [com.hikaru.crowd.mapper.UserMapper.getMaxId] [<== Total: 1]
而且需要注意的一点是,这里的mybatis也能够使用日志的原因,是@Mapper和@MapperScan两个注解(在RootConfig核心配置类中)使得mapper接口接收了IOC容器的管理,当IOC容器使用logback的时候,自然mapper接口(准确来说是mapper接口对应的IOC容器中的具体动态实现,来源于mybatis核心工厂指定的mapper配置文件)也能够使用logback
/**
* mybatis核心工厂
* @param dataSource
* @return
*/
@Bean
SqlSessionFactoryBean getSqlSessionFactoryBean(DruidDataSource dataSource) throws IOException {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
// 装配数据源
bean.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// 配置mapper映射文件地址,注意这里是getResource[s]
bean.setMapperLocations(resolver.getResources("classpath:/mapper/*.xml"));
return bean;
}
如上是不通过xml配置核心配置工厂配置mapper接口对应的mapper文件
2 声明式事务
2.1 以前的做法
try{
// 关闭事务自动提交
connection.setAutoCommit(false);
// 核心操作
Service. ...
// 提交事务
connection.commit();
} catch(Exception e) {
// 异常事务回滚
connection.rollBack();
} finally {
// 关闭链接
connection.close();
}
在AOP中,
connection.setAutoCommit(false) 对应 前置通知
connection.commit() 对应 返回通知
connection.rollBack() 对应 异常通知
connection.close() 对应 后置通知
2.2 注解的做法
而在框架环境下,可以由spring来管理通用事务操作。
@Transactional
public interface UserService {
@Transactional
public boolean addUser(User user);
}
使用Transactional注解的类或者方法会自动变为上面的类型
2.3 xml(Servlet 2.0)的做法
思路
:使用SpringAOP来进行声明式事务的配置,首先要配置一个装配数据源的事务管理器txManager
,然后在通知txAdvice
中指定使用的事务管理器,并配置一些事务属性。而AOP包括通知和切点两部分,切点pointer
则可以通过切点表达式指定,然后通过aop:advisor
将切点和通知整合。
代码
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 配置自动扫描的包:主要是为了把Service扫描到IOC容器中 -->
<context:component-scan base-package="com.hikaru.crowd.service"/>
<!-- 开启生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 装配数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务切面 -->
<aop:config>
<!-- 考虑到后面我们整合SpringSecurity,避免把UserDetailsService加入事务控制,让切入点表达式定位到ServiceImpl -->
<aop:pointcut expression="execution(* *..*ServiceImpl.*(..))" id="txPointcut"/>
<!-- 将切入点表达式和事务通知关联起来 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- 配置事务属性 -->
<tx:attributes>
<!-- 查询方法:配置只读属性,让数据库知道这是一个查询操作,能够进行一定优化 -->
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="count*" read-only="true"/>
<tx:method name="save*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
<tx:method name="remove*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
<tx:method name="batch*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
</beans>
2.4 servlet 3.0的做法
思路和xml配置是相同的,首先
① 在核心配置类RootConfig开启Aspect生成代理对象
@Configuration
@ComponentScan(value = "com.hikaru.crowd", excludeFilters = {
@ComponentScan.Filter(classes = {RestController.class})
})
@PropertySource(value = "classpath:jdbc.properties")
@MapperScan(value = "com.hikaru.crowd.mapper")
// 开启Aspect生成代理对象
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class RootConfig {
这里对应的xml:
<!-- 开启生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
② 配置事务管理器并注入数据源
/**
* 事务管理器
* @param ds
* @return
*/
@Bean
DataSourceTransactionManager getDataSourceTransactionManager(DruidDataSource ds) {
DataSourceTransactionManager dm = new DataSourceTransactionManager();
dm.setDataSource(ds);
return dm;
}
③ 创建切面并注入IOC容器
@Aspect
@Component
public class TxAdvisor {
// 声明为切点
@Pointcut("execution(* com.hikaru.crowd.service.impl.*.*(..))")
public void pointCut() {};
// 声明为前置通知
@Before("pointCut()")
public void before() {
Logger logger = LoggerFactory.getLogger(TxAdvisor.class);
logger.info("this is a info");
}
@AfterThrowing("pointCut()")
public void afterThrowing() {
Logger logger = LoggerFactory.getLogger(TxAdvisor.class);
logger.error("this is a error");
}
}
④ 测试
@Test
public void test() {
User user = new User();
user.setUserName("tod4");
user.setLoginName("tod4");
userService.addUser(user);
}
[19:46:29.235] [INFO ] [main] [com.hikaru.crowd.config.TxAdvisor] [this is a info]
但是这里是存在问题的,在ServiceImpl里面有一句除0操作,但是不仅没有触发异常通知而且甚至addUser都能正常执行。。百思不得其解,这里AOP也需要去看书补习,Spring视频讲得实在是太少了,等后面填坑写一下纯注解版的声明式事务吧
一般情况声明式事务肯定是直接使用封装好的@Transcational了!
【SSM项目】尚筹网(二)基于Servlet3.0项目搭建:日志系统以及声明式事务的更多相关文章
- Servlet3.0学习总结——基于Servlet3.0的文件上传
Servlet3.0学习总结(三)——基于Servlet3.0的文件上传 在Servlet2.5中,我们要实现文件上传功能时,一般都需要借助第三方开源组件,例如Apache的commons-fileu ...
- spring声明式事务管理方式( 基于tx和aop名字空间的xml配置+@Transactional注解)
1. 声明式事务管理分类 声明式事务管理也有两种常用的方式, 一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解. 显然基于注解的方式更简单易用,更清爽. ...
- SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务
一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...
- 零基础学习java------39---------json格式交互,Restful(不懂),静态资源映射,SSM整合(ssm整合思想,application.xml文件详解(声明式事务管理),)
一. json格式交互(知道) 1 . 回顾ajax基本语法 $.ajax({ url:"", // 请求的后台路径 data:{"":"" ...
- spring security 一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中 配置的Bean,充分利用了Spring ...
- spring事务配置,声明式事务管理和基于@Transactional注解的使用(转载)
原文地址:http://blog.csdn.net/bao19901210/article/details/41724355 事务管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...
- 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring声明式事务管理(基于Annotation注解方式实现)
在 Spring 中,除了使用基于 XML 的方式可以实现声明式事务管理以外,还可以通过 Annotation 注解的方式实现声明式事务管理. 使用 Annotation 的方式非常简单,只需要在项目 ...
- 【Spring】Spring的事务管理 - 2、声明式事务管理(实现基于XML、Annotation的方式。)
声明式事务管理 文章目录 声明式事务管理 基于XML方式的声明式事务 基于Annotation方式的声明式事务 简单记录 - 简单记录-Java EE企业级应用开发教程(Spring+Spring M ...
- Spring声明式事务管理基于@Transactional注解
概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解. 第一种方式我已在上文为大 ...
- Spring声明式事务管理基于tx/aop命名空间
目的:通过Spring AOP 实现Spring声明式事务管理; Spring支持编程式事务管理和声明式事务管理两种方式. 而声明式事务管理也有两种常用的方式,一种是基于tx/aop命名空间的xml配 ...
随机推荐
- hello cnb
Huawei executive Meng Wanzhou freed by Canada arrives home in China 目录 关于git merge冲突时候的想法 Git修改commi ...
- install package within python
import os os.system("pip install numpy") import subprocess subprocess.call(['pip3', 'insta ...
- 微信小程序按下去的样式
微信小程序设置 hover-class,实现点击态效果 目前支持 hover-class 属性的组件有三个:view.button.navigator. 不支持 hover-class 属性的组件,同 ...
- python基础学习——数据容器
1.数据容器相当于C的数组 有list,tuple(元组),str,set(集合),dict五种数据容器 2.list(列表) 列表中可存在不同的数据类型,可嵌套 #反向索引 name_list = ...
- Java基础学习——Arrays类
1.数组复制 Arrays.copyOfRange(original, from, to) 此方法与System.arraycopy类似. 不同的是System.arraycopy需要提前声明目标数组 ...
- Javaweb学习笔记第七弹
Maven依赖范围 对于Maven的安装配置等环境准备问题,可详细参考我的前几篇博客, 网址1:https://www.cnblogs.com/liuzijin/p/16654344.html 网址2 ...
- Java Swing的练习感悟
感悟心得 这还是我第一次使用Java Swing写代码呢,直接就是趣味性拉满! 在相关的界面代码的基础上,在必要的位置嵌入Java代码,就可以很好的实现啦! 简单的嘞! (有兴趣的各位可以选择去浅浅地 ...
- Nacos与OpenFeign开发
目录 1.前言 2.生产者 3.消费者 4.扩展 1.前言 我的话是微服务B调用微服务A的controller层 2.生产者 微服务A请求接口如下: @GetMapping("/listUn ...
- 干货 | BitSail Connector 开发详解系列一:Source
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 BitSail 是字节跳动自研的数据集成产品,支持多种异构数据源间的数据同步,并提供离线.实时.全量.增量场景下全 ...
- CSP-S划分 解题报告
n <= 10 爆搜即可 n <= 50 什么乱搞 n <= 400 有一个 \(n^3\) 的 dp 设 dp[i][j] 表示最后一段为 j+1~i 时的最小值 直接三层循环转移 ...