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. api接口基础Day1

    精华笔记: String: String的常用方法: length():获取字符串的长度(字符个数) trim():去除当前字符串两边的空白字符 toUpperCase()/toLowerCase() ...

  2. OSIDP-线程-04

    进程和线程 进程具有两个相互独立的特点: 1.资源所有权:进程包括存放进程映像的虚拟地址空间,具有对资源的控制权. 2.调度/执行:进程具有运行状态和优先级,是可被 OS 调度和分派的实体. 通常将分 ...

  3. JMeter线程

    线程Threads:场景设置,模拟并发用户发送请求,设置并发策略.即以线程的方式来模拟多用户并发的.常用线程包括:线程组. jp@gc-Stepping Thread Group.bzm-Arriva ...

  4. ant build 报 warning modified in the future

    错误原因:在测试项目时,修改了系统时间,之后保存了文件,再将系统时间改回来,会报这个错误 解决方法:复制改过的文件到记事本,然后回退下文件,再将记事本的内容覆盖下文件,重新build下就可以了.

  5. 【CSS】CSS字体图标iconfont

    CSS字体图标iconfont展示的是图标,本质上还是字体 使用字体图标步骤: 字体图标的下载 将字体图标引入到HTML 字体图标的追加(以后添加新的小图标) 推荐下载网站 icomoon字库http ...

  6. 使用.pem密钥文件登录服务器

    一.使用puttygen工具将.pem文件转成.ppk文件 Load时,需注意选择文件类型为All Files 二.使用secureCRT工具登录 点击properties...按钮,上传ppk文件, ...

  7. Promise async await的用法实例一枚

    getlog2() { console.log("222"); }, getlog3() { return new Promise((resolve, reject) => ...

  8. 解决 SMTP Error: data not accepted php邮件发送失败的问题

    php 发送邮件 出现  SMTP Error: data not accepted   1.正常情况下 都是正常的 但是偶尔 发送失败了 163.com 邮箱发送不了了. 所以去查了下问题所在  在 ...

  9. vue项目 运行内存溢出

    运行vue项目报错,内存溢出!!! <--- Last few GCs ---> [10400:00000218A86135D0] 173902 ms: Mark-sweep (reduc ...

  10. [imx6ull] 源码下载

    uboot git clone https://source.codeaurora.org/external/imx/uboot-imx cd uboot-imx make distclean mak ...