SSM整合(ForestBlog为例)
SSM整合(ForestBlog为例)
原版本github地址 :https://github.com/saysky/ForestBlog
文中版本地址:https://github.com/Yanshaoshuai/ForestBlog
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ForestBlog</display-name>
<!--post乱码过滤器-->
<!-- 配置springMVC编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 设置过滤器中的属性值 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 启动过滤器 -->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- 过滤所有请求 -->
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--加载spring容器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring/spring-core.xml,
</param-value>
</context-param>
<!--配置监听器,来加载spring容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 以下3项参数与log4j的配置相关 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
<!--springmvc前端控制器 -->
<servlet>
<servlet-name>ForestBlog</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ForestBlog</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--druid监控 -->
<servlet>
<servlet-name>druidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<init-param>
<!-- 允许清空统计数据 -->
<param-name>resetEnable</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>loginUsername</param-name>
<param-value>yan</param-value>
</init-param>
<init-param>
<param-name>loginPassword</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>druidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
<!--随时获得request-->
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
<!-- 4、使用Rest风格的URI,将页面普通的post请求转为指定的delete或者put请求 -->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Spring3.0中获取put表单的参数 该过滤器只能接受enctype值为application/x-www-form-urlencoded的表单-->
<filter>
<filter-name>HttpPutFormContentFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HttpPutFormContentFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--去掉jsp页面的空白-->
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
</web-app>
spring-mvc.xml
<!-- 自动扫描且只扫描SpringMVC注解 -->
<context:component-scan base-package="com.liuyanzhao.ssm.blog">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
<context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 一个配置节解决映射器和适配器的配置注解配置 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置视图解析器
进行jsp解析,默认使用jstl标签,classpath下得有jstl的包
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<!--配置前缀和后缀,也可以不指定-->
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--<!–文件上传–>-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置上传最大尺寸为50MB-->
<property name="maxUploadSizePerFile" value="52428800"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="resolveLazily" value="true"/>
</bean>
<!-- 静态资源映射 -->
<mvc:resources mapping="/css/**" location="/resource/assets/css/"></mvc:resources>
<mvc:resources mapping="/js/**" location="/resource/assets/js/"></mvc:resources>
<mvc:resources mapping="/img/**" location="/resource/assets/img/"></mvc:resources>
<mvc:resources mapping="/plugin/**" location="/resource/assets/plugin/"></mvc:resources>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.liuyanzhao.ssm.blog.interceptor.HomeResourceInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/admin"/>
<bean class="com.liuyanzhao.ssm.blog.interceptor.SecurityInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/admin/**"/>
<bean class="com.liuyanzhao.ssm.blog.interceptor.SecurityInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
spring-core.xml
<!-- 组件扫描排除SpringMVC注解 -->
<context:component-scan base-package="com.liuyanzhao.ssm.blog">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.RestController"/>
<context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 开启注解支持-->
<context:annotation-config/>
<import resource="spring-mybatis.xml"/>
spring-mybatis.xml
<!--加载db.properties-->
<context:property-placeholder location="classpath:db.properties"/>
<!--配置druid连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 基本属性 url、user、password -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="${mysql.url}" />
<property name="username" value="${mysql.username}" />
<property name="password" value="${mysql.password}" />
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="1" />
<property name="minIdle" value="1" />
<property name="maxActive" value="20" />
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="60000" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 'x'" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
<!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
<property name="filters" value="stat" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--数据库连接池-->
<property name="dataSource" ref="dataSource"/>
<!--加载mybatis全局配置文件-->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/>
<!--mapper.xml所在位置-->
<property name="mapperLocations" value="classpath*:mapper/*Mapper.xml" />
<!--指定需要使用别名的PO类所在的包-->
<property name="typeAliasesPackage" value="com.liuyanzhao.ssm.blog.entity" />
</bean>
<!--mapper扫描器-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--如果需要扫描多个包,中间使用半角逗号隔开-->
<property name="basePackage" value="com.liuyanzhao.ssm.blog.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 对mybatis操作数据事务控制,spring使用jdbc的事务控制类 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 数据源dataSource在spring-mybatis.xml中配置了 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.liuyanzhao.ssm.blog.service.impl.*.*(..))"/>
</aop:config>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局配置 -->
<settings>
<!--允许 JDBC 支持自动生成主键-->
<setting name="useGeneratedKeys" value="false"/>
<!--是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典
Java 属性名 aColumn 的类似映射。 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!--<property name="dialect" value="mysql"/>-->
<property name="offsetAsPageNum" value="false"/>
<property name="rowBoundsWithCount" value="false"/>
<property name="pageSizeZero" value="true"/>
<property name="reasonable" value="true"/>
<property name="supportMethodsArguments" value="false"/>
<property name="returnPageInfo" value="none"/>
</plugin>
</plugins>
</configuration>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.liuyanzhao</groupId>
<artifactId>ForestBlog</artifactId>
<packaging>war</packaging>
<version>1.0.0-SNAPSHOT</version>
<name>ForestBlog Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<!-- 添加sevlet支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- 添加jsp支持 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- 添加jstl支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- 添加spring支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!--spring test支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!--spring mvc支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!--spring 事务管理支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!--spring jdbc操作支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!--spring aop编程支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!-- 添加mybatis支持 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- jdbc驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<!-- 添加阿里巴巴连接池Druid支持 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.16</version>
</dependency>
<!-- 添加log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<!-- 添加junit支持 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20170516</version>
</dependency>
<dependency>
<groupId>com.googlecode.rapid-framework</groupId>
<artifactId>rapid-core</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>26.0-jre</version>
</dependency>
<!--运行时进不来,暂时手动添加jar包-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.2.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!-- hutool工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.1.13</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.apache.tomcat.embed</groupId>-->
<!-- <artifactId>tomcat-embed-core</artifactId>-->
<!-- <version>8.5.47</version>-->
<!-- </dependency>-->
</dependencies>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<resources>
<!-- 编译之后包含xml -->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<!-- 编译之后包含xml和properties -->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
SSM整合(ForestBlog为例)的更多相关文章
- spring MVC框架入门(外加SSM整合)
spring MVC框架 一.什么是sping MVC Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 W ...
- 08 SSM整合案例(企业权限管理系统):10.权限关联与控制
04.AdminLTE的基本介绍 05.SSM整合案例的基本介绍 06.产品操作 07.订单操作 08.权限控制 09.用户操作 10.权限关联与控制 11.AOP日志 10.权限关联与控制 1.用户 ...
- Maven + 最新SSM整合
. 1. 开发环境搭建 参考博文:Eclipse4.6(Neon) + Tomcat8 + MAVEN3.3.9 + SVN项目完整环境搭建 2. Maven Web项目创建 2.1. 2.2. 2. ...
- SSM整合配置
SSM三大框架整合详细教程(Spring+SpringMVC+MyBatis) 使用SSM(Spring.SpringMVC和Mybatis)已经有三个多月了,项目在技术上已经没有什么难点了,基于现有 ...
- SSM整合中遇到的不能扫描注解的bug
我的开发环境为: ubuntu14.04LTS 64bit; Spring Tool Suite 3.5.0.RELEASE Maven 3.2.3 SSM整合中遇到的不能扫描注解的bug 最终解决 ...
- 基于Maven的SSM整合的web工程
此文章主要有以下几个知识点: 一.如何创建 Maven的Web 工程 二.整合SSM(Spring,SpringMvc,Mybatis),包括所有的配置文件 三.用 mybatis 逆向工程生成对应的 ...
- ssm整合说明与模板-Spring Spring MVC Mybatis整合开发
ssm整合说明 spring+spring mvc+mybatis 说明 源码下载 由于之前存在ssh框架,spring+struts+hibernate,其中spring负责aop与ioc,所以一般 ...
- 04.redis集群+SSM整合使用
redis集群+SSM整合使用 首先是创建redis-cluster文件夹: 因为redis最少需要6个节点(三主三从),为了更好的理解,我这里创建了两台虚拟机(192.168.0.109 192.1 ...
- SSM整合---实现全部用户查询
SSM整合 准备 1.创建工程 2.导入必须jar包 链接: https://pan.baidu.com/s/1nvCDQJ3 密码: v5xs 3.工程结构 代码 SqlMapConfig < ...
随机推荐
- WordPress的SEO优化技巧
世界上大约有30%的网站都是由Wordpress搭建的,因为Wordpress自身构架清晰,代码规范,且网页评论直接书写在整个页面里,能够被搜索引擎检索到,因此对搜索引擎很友好.但有时候还是会出现只被 ...
- MySQL常见的七种锁详细介绍()
原地址: https://blog.csdn.net/Saintyyu/article/details/91269087
- docker命令快速入门
docker快速入门系列 Docker hello world hello world $ docker run ubuntu:15.10 /bin/echo "Hello world&qu ...
- Install Tensorflow object detection API in Anaconda (Windows)
This blog is to explain how to install Tensorflow object detection API in Anaconda in Windows 10 as ...
- 做个开源博客学习Vite2 + Vue3 (一)搭建项目
前言 不会 webpack,遇到报错就一头雾水,完全不知道怎么办,而且体积还大速度还慢. 所以尤雨溪做了 vite 后就很向往,只是知道自己水平有限还是等大佬先趟趟坑,等差不多了在跳. 现在vite2 ...
- matlab文件管理
当前文价夹浏览器以及路径管理器 在主页面左侧有单独的窗口进行显示,可以显示当前目录下的文件并提供文件搜索功能. 搜索路径 搜索先后步骤 输入字符串"polyfit" (1)检查 ...
- 02- linux目录和文件的基础操作
本博文纲要 linux目录结构 绝对路径与相对路径 linux目录常用操作 linux文件常用操作 Q/A Windows文件系统特点 -文件系统是操作系统的一个功能,用户管理目录和文件 -Windo ...
- 03 Django web服务开发 - URL路由
Django中的APP -Django中的一个APP就是一个应用的意思 -项目可以包含多个APP(多个应用) -一个项目对应一个网站(生活服务网站) 一个APP队形网站的一个应用(二手交易,家政服务) ...
- 分享几个网址二维码生成api
分享几个网址二维码生成api 传入网址参数,或许二维码图片,扫二维码能直接跳转网址 http://b.bshare.cn/barCode?site=weixin&url=https://www ...
- 【日志】MySQL中有多少种日志
redo 重做日志 作用:确保事务的持久性,防止在发生故障,脏页未写入磁盘.重启数据库会进行redo log执行重做,到达事务一致性 undo 回滚日志 作用:保证数据的原子性,记录事务发生之前的数据 ...