文章目录
SSM整合
整合Spring、SpringMVC、MyBatis,搭建SSM环境,用于开发其他功能。
整合思路
- 搭建整合的环境,初始化环境
- 搭建Spring环境,配置完成并测试
- 再使用Spring整合SpringMVC框架,并测试
- 最后使用Spring整合MyBatis框架,并测试
整合方法:xml配置+注解
的方式进行整合。
1. 搭建SSM环境
1.1 准备一个ssm数据库,并创建person表用于测试
CREATE DATEBASE ssm;
USE ssm;
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`money` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `person` VALUES ('1', 'striveday', '10000');
INSERT INTO `person` VALUES ('2', 'studyday', '20000');
1.2 pom.xml
导入依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.2.9.RELEASE</spring.version>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<mysql.version>5.1.6</mysql.version>
<mybatis.version>3.4.5</mybatis.version>
</properties>
<dependencies>
<!-- spring -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
1.3 配置log4j日志属性文件log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
# 输出到控制台
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
# 输出到日志文件
log4j.appender.LOGFILE.File=E:\logFile\SSM\ssm.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
2. Spring配置测试IOC和DI
2.1 创建测试类,测试控制反转和依赖注入,测试方法调用
//用spring自带的test测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestPersonService {
//日志
private static final Logger log = Logger.getLogger(TestPersonService.class.getName());
//自动装载
@Autowired
IPersonService personService;
//测试IOC DI依赖注入是否成功
@Test
public void test01(){
System.out.println(personService);
}
//测试查询方法
@Test
public void test02(){
//记录日志
log.info(personService+"");
//查询所有
List<Person> list = personService.findAll();
//调用保存
log.info("allPerson:"+list+"");
}
//测试增加方法
@Test
public void test03(){
Person person = new Person(null,"striveday",20000000.68);
personService.savePerson(person);
List<Person> list = personService.findAll();
log.info("allPerson:"+list+"");
}
}
2.2 创建javabean对象person
public class Person {
private Integer id;
private String name;
private Double money;
//省略get/set方法
}
2.3 创建测试业务接口IPersonService
及其实现类PersonServiceImpl
public interface IPersonService {
//查找所有person
List<Person> findAll();
//新增一个person
int savePerson(Person person);
}
@Service
public class PersonServiceImpl implements IPersonService {
@Autowired
private IPersonDao personDao;
@Override
public List<Person> findAll() {
List<Person> allPersonList = personDao.findAll();
return allPersonList;
}
@Override
public int savePerson(Person person) {
int code = personDao.savePerson(person);
return code;
}
}
2.4 创建dao层接口IPersonDao
及其实现类PersonDaoImpl
,因为没有整合MyBatis,所以就不进行xml映射配置,所以这里用PersonDaoImpl实现类
public interface IPersonDao {
//查询所有用户
List<Person> findAll();
//新增一个person
int savePerson(Person person);
}
@Repository
public class PersonDaoImpl implements IPersonDao {
@Override
public List<Person> findAll() {
System.out.println("findAll");
//因为没有整合mybatis,这里设置初始化数据进行模拟
List<Person> personList = null;
personList.add(new Person(null,"studyday",10000.0));
personList.add(new Person(null,"striveday",20000.0));
return personList;
}
@Override
public int savePerson(Person person) {
System.out.println("savePerson");
return 1;
}
}
2.5 配置spring核心配置文件applicationContext.xml
这里面很多xml约束还没有用到,但是一起弄过来了,反正后面会用到
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 设置扫描包,包下设置注解@Service @Repository @Component @AutoWried-->
<context:component-scan base-package="com.xgf">
<!-- 由于springmvc的controller是由springmvc来扫描,需要将controller排除在外-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
2.6 测试IOC(DI)是否可以注入,测试方法是否可以执行。
- 测试(IOC/DI)测试test01方法
- 测试查询方法test02
- 测试save方法test03
测试Spring没有什么bug,我们就可以继续往下整合了。
3. Spring整合SpringMVC框架
我们知道servlet做三件事(接收请求,处理参数,返回结果)
springmvc就只有一个servlet,也就是DispatcherServlet
前端控制器,但是它不处理参数,只是将请求分发,交给对应的controller
控制器来处理参数
3.1 web.xml配置
web.xml
中配置前端控制器DispatcherServlet
、编码过滤器CharacterEncodingFilter
、监听器ContextLoaderListener
和spring核心配置文件的路径参数context-param
- (1) web.xml中配置前端控制器
DispatcherServlet
SpringMVC的核心就是DispatcherServlet,DispatcherServlet实质也是一个HttpServlet。DispatcherSevlet负责将请求分发给对应的
Controller
,所有的请求都有经过它来统一分发。
- (2)web.xml中配置编码过滤器
CharacterEncodingFilter
在 SpringMVC 中,框架直接给我们提供了一个用来解决请求和响应的乱码问题的过滤器 CharacterEncodingFilter
- (3)web.xml中配置编码监听器
ContextLoaderListener
web.xml中的配置文件中ContextLoaderListener作为监听器,会监听web容器相关事件,在web容器启动或者关闭时触发执行响应程序。
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--这些配置是有顺序的 context-param参数,后面是filter过滤器,然后是listener监听器,然后是servlet前端控制器 -->
<!--设置spring核心配置文件的路径 后面会整合mybatis,所以这个调用的是service,dao层 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 配置过滤器characterEncodingFilter 解决中文乱码(统一编码) -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<!-- spring自带编码过滤器 -->
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!-- 读取键值对 key-取名 value-设置的编码 -->
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!-- /*拦截所有请求,都要被过滤器过滤 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置Spring的监听器,默认只加载WEB-INF目录下的applicationContext.xml配置文件-->
<listener>
<!-- ContextLoaderListener监听器的作用就是启动Web容器时,自动装配applicationContext的配置信息 -->
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--配置前端控制器,进行接收请求转发至controller,解决Controller的问题(web层)-->
<servlet>
<!-- 前端控制器取名 可以更改,但是要和下面的一样 -->
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--加载springmvc.xml配置文件-->
<init-param>
<!-- 整合SpringMVC,需要加载springmvc核心配置文件 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--数字越大优先级越低, 数字为1,启动服务器,立即创建该servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!-- 要和上面的前端控制器命名相同 -->
<servlet-name>DispatcherServlet</servlet-name>
<!-- / 表示所有请求都拦截 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
【注意】配置是有顺序的,要按照这个顺序来执行(参数 -> 过滤器 -> 监听器 -> servlet前端控制器)。
这是配置顺序:
icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*
3.2 配置SpringMVC核心配置文件springmvc.xml
在springmvc中配置视图解析器,开启组件扫描,开启注解驱动,配置springmvc对静态资源文件的放行(前端控制器DispatcherServlet
拦截所有请求,我们需要对静态资源文件css/js/img之类的方向不拦截)。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--springmvc是web层(Controller处理请求) UserController @Controller -->
<!-- 打开组件扫描器,只扫描Controller层 -->
<context:component-scan base-package="com.xgf">
<!-- 只处理带@Controller注解的文件 -->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--配置的视图解析器对象,路径/WEB-INF/pages/success.jsp -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--配置文件 - 过滤静态资源 前面的前端控制器拦截所有,静态css、js这些也都拦截
配置使.js .css img fonts这些静态文件不被拦截,保证静态文件都不拦截
用过mvc标签进行放行,这些目录下文件都不拦截 -->
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/images/" mapping="/images/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<mvc:resources location="/fonts/" mapping="/fonts/**" />
<!-- 开启注解驱动,开启SpringMVC的注解的支持 @RequestMapping @RequestBody @ResponseBody这些注解需要使用 -->
<mvc:annotation-driven/>
</beans>
3.3 编写数据进行测试
- 编写一个
PersonController
@Controller
@RequestMapping("/person")
public class PersonController {
@Autowired
private IPersonService personService;
@RequestMapping(path="/list",method = RequestMethod.GET)
public String list(Model model){
//显示所有的person数据
List<Person> personList = personService.findAll();
System.out.println("list() personList= "+personList);
//数据放在Model对象,由Model传给页面
model.addAttribute("personList",personList);//参1 key 参2 value
return "personList";//返回list页面
}
}
- 编写一个
perosnList.jsp
页面进行展示数据
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table border="1px" width="100%">
<c:forEach items="${personList}" var="person">
<tr>
<td>${person.id}</td>
<td>${person.name}</td>
<td>${person.money}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
- 运行结果,显示成功,Spring整合SpringMVC成功。
4. Spring整合MyBatis
整合记得一点,先测试没有问题,再整合进去!!(Spring整合MyBatis 需要mybatis-spring
整合包)
4.1 配置Mybatis,并测试MyBatis
- 配置MyBatis核心配置文件
SqlMapConfig.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>
<!-- 定义别名 全名:com.xgf.bean.Person 可以简写为别名:person-->
<typeAliases>
<package name="com.xgf.bean"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<!-- MyBatis自带连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
<property name="username" value="root"/>
<property name="password" value="861221293"/>
</dataSource>
</environment>
</environments>
<!-- 核心 配置文件扫描到映射文件-->
<mappers>
<package name="com.xgf.dao"/>
</mappers>
</configuration>
- 测试MyBatis连接数据库进行操作是否有问题
TestMyBatis
public class TestMyBatis {
private static SqlSessionFactory factory;
private SqlSession session;
//@BeforeClass只在类中执行一次, 必须声明为public static
@BeforeClass
public static void getFactory(){
// 加载配置文件
InputStream in = TestMyBatis.class.getClassLoader().getResourceAsStream("SqlMapConfig.xml");
// 创建SqlSessionFactory对象
factory = new SqlSessionFactoryBuilder().build(in);
}
//@Before在每个测试方法之前都执行一次, 方法需要声明为public
@Before
public void init(){
// 每个方法执行前创建SqlSession对象
session = factory.openSession();
}
//每个方法执行结束进行提交和关闭
@After
public void destory(){
session.commit();
session.close();
}
//查询所有person
@Test
public void test01(){
//最核心对象是session
// System.out.println(session);
//Mybastis的特点是sql与代码是分开的,需要映射文件,通过getMapper生成代理类
IPersonDao personDao = session.getMapper(IPersonDao.class);
List<Person> personList = personDao.findAll();
System.out.println(personList);
}
//保存person
@Test
public void test02(){
//最核心对象是session
IPersonDao dao = session.getMapper(IPersonDao.class);
dao.savePerson(new Person(null,"strive_day",200.00));
}
}
- 创建dao层接口映射文件
IPersonDao.xml
(这里就不需要有dao层的实现类了,可以注释掉PersonDaoImpl
或者在上面加注解@Deprecated
表示该类过时)
在resources
目录下创建和IPersonDao
相同的路径(因为idea会将接口和文件编译合在一起叫类路径)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xgf.dao.IPersonDao">
<!-- resultType我开启了别名所以用别名就行 -->
<select id="findAll" resultType="person">
select id,name,money from person;
</select>
<insert id="savePerson" parameterType="person">
insert into person (name,money)values(#{name},#{money})
</insert>
</mapper>
- 测试MyBatis环境,执行测试方法
测试test01
查询所有person
测试test02
增加person
测试MyBatis没有什么问题,我们就可以将MyBatis整合到Spring中去了。
4.2 Spring整合MyBatis,配置数据库连接池c3p0,整合mybatis核心配置到spring核心配置文件中。
Spring整合MyBatis需要一个整合包mybatis-spring
,前面已经导入了,这里只是强调一下。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
MyBatis-Spring
会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中。
以后不需要调用 session.getMapper(IpersonDao.class)来获取代理类了,事务的提交和删除(写操作)也不需要了(session.commit(),session.close())
4.2.1 创建数据库连接的属性文件c3p0.properties
#c3p0连接池属性文件
# 四大基本信息
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8&useSSL=false
c3p0.user=root
c3p0.password=861221293
# 初始化连接数 取值要在minPoolSize和maxPoolSize之间(可包含,闭区间) 默认值:3
c3p0.initialPoolSize=10
# 最大连接数 (连接池中的连接数不能超过maxPoolSize最大连接数) 默认值:15
c3p0.maxPoolSize=50
#最小连接数 默认值:3
c3p0.minPoolSize=5
#c3p0连接池中数据连接不够时(无空闲连接可用),一次增长的个数(增长不能超过maxPoolSize最大连接个数) 默认值:3
c3p0.acquireIncrement=5
#连接的最大空闲时间,如果超过这个时间还没有被使用,就断开这个连接(设置为0或负数,就永远都不会被断开) 单位:秒 默认值 :0
c3p0.maxIdleTime=600
#从数据库获取新连接失败后重复尝试的次数。小于等于0表示无限次 默认值: 30
c3p0.acquireRetryAttempts=30
#两次连接的中间间隔时间(重新尝试的时间间隔) 单位:毫秒 默认值:1000
c3p0.acquireRetryDelay=1000
#连接关闭时,是否将所有未提交的操作进行事务回滚 默认值:false
c3p0.autoCommitOnClose = false
#当连接池用完时,客户端调用getConnection()后等待获取新连接的时间 单位:毫秒 默认值:0 (无限期等待) 按照设置的值,超时将抛出SQLException异常
c3p0.checkoutTimeout = 0
#每隔多少秒检查所有连接池中的空闲连接 单位:秒 默认值:0
c3p0.idleConnectionTestPeriod=60
#配置PreparedStatement缓存,设置连接池为数据源缓存的PreparedStatement的总数,为0的时候不缓存,同时maxStatementsPerConnection的配置无效。
# 由于PreparedStatement属于单个Connection,所以这个数量应该根据应用中平均连接数乘以每个连接的平均PreparedStatement来计算
c3p0.maxStatements=1000
# 连接池为数据源单个Connection缓存的PreparedStatement数,这个配置比maxStatements更有意义,因为它缓存的服务对象是单个数据连接,如果设置的好,肯定是可以提高性能的。为0的时候不缓存。
# c3p0.maxStatementsPerConnection
4.2.2 在applicationContext.xml中配置c3p0数据库连接池
将MyBatis核心配置文件 SqlMapConfig
都整入Spring核心配置文件applicationContext.xml
中,交给Spring来管理。
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 引入c3p0的属性文件(里面是连接数据库四大信息键值对),在配置中通过占位使用 -->
<context:property-placeholder location="classpath:c3p0.properties" />
<!-- 连接数据库的四大基本信息-->
<!-- 数据库连接池c3p0 -->
<!-- 用c3p0数据源配置连接池,里面有连接池 ComboPooledDataSource数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 连接池4大组件 -->
<property name="driverClass" value="${c3p0.driverClass}"/>
<property name="jdbcUrl" value="${c3p0.jdbcUrl}"/>
<property name="user" value="${c3p0.user}"/>
<property name="password" value="${c3p0.password}"/>
<!--初始化连接数 取值要在minPoolSize和maxPoolSize之间(可包含,闭区间) 默认值:3 -->
<property name="initialPoolSize" value="${c3p0.initialPoolSize}"/>
<!-- 最大连接数 (连接池中的连接数不能超过maxPoolSize最大连接数) 默认值:15-->
<property name="maxPoolSize" value="${c3p0.maxPoolSize}"/>
<!--最小连接数 默认值:3 -->
<property name="minPoolSize" value="${c3p0.minPoolSize}"/>
<!-- c3p0连接池中数据连接不够时(无空闲连接可用),一次增长的个数(增长不能超过maxPoolSize最大连接个数) 默认值:3 -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}"/>
<!-- 连接的最大空闲时间,如果超过这个时间还没有被使用,就断开这个连接(设置为0或负数,就永远都不会被断开) 单位:秒 默认值 :0 -->
<property name="maxIdleTime" value="${c3p0.maxIdleTime}"/>
<!-- 从数据库获取新连接失败后重复尝试的次数。小于等于0表示无限次 默认值: 30-->
<property name="acquireRetryAttempts" value="${c3p0.acquireRetryAttempts}"/>
<!-- 两次连接的中间间隔时间(重新尝试的时间间隔) 单位:毫秒 默认值:1000 -->
<property name="acquireRetryDelay" value="${c3p0.acquireRetryDelay}"/>
<!-- 连接关闭时,是否将所有未提交的操作进行事务回滚 默认值:false -->
<property name="autoCommitOnClose" value="${c3p0.autoCommitOnClose}"/>
<!-- 当连接池用完时,客户端调用getConnection()后等待获取新连接的时间 单位:毫秒 默认值:0
如果值设为 0,将无限期等待,直到有空闲连接。 否则按照设置的值,超时将抛出SQLException异常
时间设置过小时会出现连接超时,这样会抛出SQLException异常,设置时间时需要小心,按照实际情况设置适当的值-->
<property name="checkoutTimeout" value="${c3p0.checkoutTimeout}"/>
<!-- 每隔多少秒检查所有连接池中的空闲连接 单位:秒 默认值:0 -->
<property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"/>
<!-- 配置PreparedStatement缓存,设置连接池为数据源缓存的PreparedStatement的总数
为0的时候不缓存,同时maxStatementsPerConnection的配置无效。
由于PreparedStatement属于单个Connection,所以这个数量应该根据应用中平均连接数乘以每个连接的平均PreparedStatement来计算-->
<property name="maxStatements" value="${c3p0.maxStatements}"/>
</bean>
<!-- 设置扫描包,包下设置注解@Service @Repository @Component @AutoWried-->
<context:component-scan base-package="com.xgf">
<!-- 由于springmvc的controller是由springmvc来扫描,需要将controller排除在外-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
</beans>
4.2.3 在applicationContext.xml中配置session工厂和编译后dao目录文件扫描
<!-- 获取sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"/>
<!-- 给整个包下的所有文件起别名,就是类名的首字母小写 com.xgf.bean.Person 简化成 person-->
<property name="typeAliasesPackage" value="com.xgf.bean"/>
</bean>
<!-- 配置映射文件扫描器 : IPersonDao.xml和IPersonDao.java-->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描dao接口和映射xml编译后的类路径 -->
<property name="basePackage" value="com.xgf.dao"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
4.2.4 测试配置c3p0数据源能否拿到连接,并测试查询和新增
//测试c3p0数据库连接池,数据源是否配置对,能否拿到连接
//测试查询person、增加person
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestC3p0DataSource {
private static final Logger log = Logger.getLogger(TestC3p0DataSource.class.getName());
@Autowired
DataSource dataSource;
//测试能否通过链接拿到数据
@Test
public void testDataSource() throws SQLException {
log.info("testDataSource获取连接:"+dataSource.getConnection());
}
@Autowired
IPersonDao personDao;
//测试查询
@Test
public void test01(){
List<Person> personList = personDao.findAll();
System.out.println(personList);
}
//测试新增
@Test
public void test02(){
Person person = new Person(null,"TestC3p0DataSource",200.00);
personDao.savePerson(person);
}
}
测试testDataSource(),看能否从c3p0拿到连接
测试testDataSource()
测试结果:能够拿到连接,并初始化了十个连接
测试配置c3p0数据库连接池之后对数据库操作:
测试test01方法,进行查询所有person
测试test02方法,保存一个person
4.3 Spring整合MyBatis,配置事务管理,让Spring来管理事务
spring事务的底层是AOP,做一个转账功能或者批量保存功能来验证是否能满足条件(一个事务必须全部执行或者全部不执行,查看错误是否发生事务回滚就行)
这里通过批量增加person,出现除零(1/0)错误,查看是否事务回滚。
4.3.1 applicationContext.xml配置事务管理
这里配置的事务,是以find*、save*、delete*、update*
开头的,所以按照这种配置,只有以这些开头的才进行事务管理,且find*开头的是不进行事务管理的(查询不需要),其他修改操作就需要进行事务管理。
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- spring提供的tx标签对方法进行分类 -->
<tx:attributes>
<!-- 方法:所有以find开头的都不进行事务管理(以后查询都以find开头) -->
<tx:method name="find*" read-only="true"/>
<!-- 其他的都用默认的DEFAULT,进行事务管理
(DEFAULT是默认的事务隔离级别,mysql用什么事务隔离级别我们也用) -->
<tx:method name="delete*" isolation="DEFAULT"/>
<tx:method name="save*" isolation="DEFAULT"/>
<tx:method name="update*" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP实现增强,配置aop事务 -->
<aop:config>
<!-- expression表达式的值,按照你的路径配置
* com.xgf.service.impl.*ServiceImpl.*(..))
第一个* 是返回值通配符
然后是包的路径,*ServiceImpl表示配置的所有满足类名+ServiceImpl后缀的且在com.xgf.service.impl目录下的
*(..) : *表示所有方法 (..)表示匹配所有参数
-->
<aop:pointcut id="service" expression="execution(* com.xgf.service.impl.*ServiceImpl.*(..))"/>
<!-- 切入点 一个增强通知以及一个说明在何处增强的切入点 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="service"/>
</aop:config>
4.3.2 dao、service和serviceImpl写savePersonList
保存多个person
IPersonDao
@Repository
public interface IPersonDao {
//保存多个person
int savePersonList(List<Person> personList);
}
IPersonService
public interface IPersonService {
//增加多个person
int savePersonList(List<Person> personList);
}
@Service
public class PersonServiceImpl implements IPersonService {
@Autowired
private IPersonDao personDao;
@Override
public int savePersonList(List<Person> personList) {
int code = personDao.savePersonList(personList);
return code;
}
}
4.3.3 映射文件IPersonDao.xml插入多个person
<!-- 插入多条数据,进行事务测试 -->
<!-- 使用foreach元素,插入多条用户信息 -->
<!-- 插入一条:insert into person (name,money)values(#{name},#{money})
这里接收的参数是personList,参数类型是java.util.List
循环遍历要用 collection="list"
-->
<insert id="savePersonList" parameterType="java.util.List">
insert into person(name,money)values
<foreach item="item" index="index" separator="," collection="list">
(#{item.name},#{item.money})
</foreach>
</insert>
4.3.4 测试
- 正常测试,没有1/0错误代码
//模拟看是否发生事务回滚 批量保存(保存的过程中有一个地方抛出异常,就应该全部回滚)
@Test
public void test04(){
List<Person> personList = new ArrayList<>();
personList.add(new Person(null,"savePerson_001",100.00));
personList.add(new Person(null,"savePerson_002",200.00));
personList.add(new Person(null,"savePerson_003",300.00));
int code = personService.savePersonList(personList);
log.info("插入" + code + "条person数据");
}
- 有异常抛出(1/0) by zero异常,看事务是否回滚
//模拟看是否发生事务回滚 批量保存(保存的过程中有一个地方抛出异常,就应该全部回滚)
@Test
public void test04(){
List<Person> personList = new ArrayList<>();
personList.add(new Person(null,"savePerson_001",100.00));
personList.add(new Person(null,"savePerson_002",200.00));
//抛出1/0异常
System.out.println(1/0);
personList.add(new Person(null,"savePerson_003",300.00));
int code = personService.savePersonList(personList);
log.info("插入" + code + "条person数据");
}