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项目搭建:日志系统以及声明式事务的更多相关文章

  1. Servlet3.0学习总结——基于Servlet3.0的文件上传

    Servlet3.0学习总结(三)——基于Servlet3.0的文件上传 在Servlet2.5中,我们要实现文件上传功能时,一般都需要借助第三方开源组件,例如Apache的commons-fileu ...

  2. spring声明式事务管理方式( 基于tx和aop名字空间的xml配置+@Transactional注解)

    1. 声明式事务管理分类 声明式事务管理也有两种常用的方式, 一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解. 显然基于注解的方式更简单易用,更清爽. ...

  3. SSM实战——秒杀系统之Service层接口设计与实现、Spring托管、声明式事务

    一:Service层接口设计 准备工作:新建三个包:service包.exception包.dto包,分别用来存放业务接口.自定义异常类.dto类. 1:定义接口 package org.myseck ...

  4. 零基础学习java------39---------json格式交互,Restful(不懂),静态资源映射,SSM整合(ssm整合思想,application.xml文件详解(声明式事务管理),)

    一. json格式交互(知道) 1 . 回顾ajax基本语法 $.ajax({ url:"", // 请求的后台路径 data:{"":"" ...

  5. spring security 一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中 配置的Bean,充分利用了Spring ...

  6. spring事务配置,声明式事务管理和基于@Transactional注解的使用(转载)

    原文地址:http://blog.csdn.net/bao19901210/article/details/41724355 事务管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的 ...

  7. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring声明式事务管理(基于Annotation注解方式实现)

    在 Spring 中,除了使用基于 XML 的方式可以实现声明式事务管理以外,还可以通过 Annotation 注解的方式实现声明式事务管理. 使用 Annotation 的方式非常简单,只需要在项目 ...

  8. 【Spring】Spring的事务管理 - 2、声明式事务管理(实现基于XML、Annotation的方式。)

    声明式事务管理 文章目录 声明式事务管理 基于XML方式的声明式事务 基于Annotation方式的声明式事务 简单记录 - 简单记录-Java EE企业级应用开发教程(Spring+Spring M ...

  9. Spring声明式事务管理基于@Transactional注解

    概述:我们已知道Spring声明式事务管理有两种常用的方式,一种是基于tx/aop命名空间的xml配置文件,另一种则是基于@Transactional 注解.         第一种方式我已在上文为大 ...

  10. Spring声明式事务管理基于tx/aop命名空间

    目的:通过Spring AOP 实现Spring声明式事务管理; Spring支持编程式事务管理和声明式事务管理两种方式. 而声明式事务管理也有两种常用的方式,一种是基于tx/aop命名空间的xml配 ...

随机推荐

  1. hello cnb

    Huawei executive Meng Wanzhou freed by Canada arrives home in China 目录 关于git merge冲突时候的想法 Git修改commi ...

  2. install package within python

    import os os.system("pip install numpy") import subprocess subprocess.call(['pip3', 'insta ...

  3. 微信小程序按下去的样式

    微信小程序设置 hover-class,实现点击态效果 目前支持 hover-class 属性的组件有三个:view.button.navigator. 不支持 hover-class 属性的组件,同 ...

  4. python基础学习——数据容器

    1.数据容器相当于C的数组 有list,tuple(元组),str,set(集合),dict五种数据容器 2.list(列表) 列表中可存在不同的数据类型,可嵌套 #反向索引 name_list = ...

  5. Java基础学习——Arrays类

    1.数组复制 Arrays.copyOfRange(original, from, to) 此方法与System.arraycopy类似. 不同的是System.arraycopy需要提前声明目标数组 ...

  6. Javaweb学习笔记第七弹

    Maven依赖范围 对于Maven的安装配置等环境准备问题,可详细参考我的前几篇博客, 网址1:https://www.cnblogs.com/liuzijin/p/16654344.html 网址2 ...

  7. Java Swing的练习感悟

    感悟心得 这还是我第一次使用Java Swing写代码呢,直接就是趣味性拉满! 在相关的界面代码的基础上,在必要的位置嵌入Java代码,就可以很好的实现啦! 简单的嘞! (有兴趣的各位可以选择去浅浅地 ...

  8. Nacos与OpenFeign开发

    目录 1.前言 2.生产者 3.消费者 4.扩展 1.前言 我的话是微服务B调用微服务A的controller层 2.生产者 微服务A请求接口如下: @GetMapping("/listUn ...

  9. 干货 | BitSail Connector 开发详解系列一:Source

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 BitSail 是字节跳动自研的数据集成产品,支持多种异构数据源间的数据同步,并提供离线.实时.全量.增量场景下全 ...

  10. CSP-S划分 解题报告

    n <= 10 爆搜即可 n <= 50 什么乱搞 n <= 400 有一个 \(n^3\) 的 dp 设 dp[i][j] 表示最后一段为 j+1~i 时的最小值 直接三层循环转移 ...