Maven构建SpringMVC项目实现注解及数据库事务管理

Maven构建SpringMVC项目实现注解及数据库事务管理

背景介绍

构建工程

本项目搭建工具使用Eclipse。

用maven插件构建项目框架

打开菜单File –New-MavenProject,点击Next,选择maven-archetype-webapp,点击Next,如下图:

img

输入Group Id和artifact Id。Group Id一般填入项目名称,Artifact Id一般填入子项目的名称,如下图,点击完成

img

等待构建完成,生成的项目文件结构如下图所示:

img

点击pom.xml文件,进入编辑界面,如下图: pom文件

增加Properties:展开Properties选项,然后点击Create…按钮,如下图所示:然后Name字段填入springVersion,Value字段填入3.2.5.RELEASE。即在pom.xml中增加了一个属性springVersion,属性值为3.2.5.RELEASE(此处value是根据自己所使用的Spring版本设置,由于本人使用的是3.2.5版本,所以填入3.2.5.RELEASE)。

img

增加Dependency:点击Dependencies标签,进入Dependencies编辑界面,点击Add…,添加Dependency属性,此过程是加入springframe的spring-web依赖库,${springVersion}是之前设置的属性,过程如下图所示:

Group Id:org.springframework

Artifact Id:spring-web

Version:${springVersion}

点击确定按钮。

img

同理再新建一个Dependency,该过程是加入springframe的spring-webmvc依赖库,${springVersion}是之前设置的属性,具体属性值如下所示:

Group Id:org.springframework

Artifact Id:spring-webmvc

Version:${springVersion}

点击确定按钮。

设置完成之后,Ctrl+S保存,Maven会自动构建工作空间,下载所需要的依赖库文件,下载完成之后,可以看到如下图所示的库文件:

目录结构

img

注意事项:
​ 由于后面会用到C3P0连接池,事务管理,mysql数据库驱动,所以还需要导入如左图蓝色标识的jar包

添加Source Fold

完善目录,添加source folder(源文件夹)。添加src/main/java,src/test/resources,src/test/java目录,让目录变成标准的maven结构,如下图:

img

img

注意:如果Eclipse建立Maven项目后无法建立src/main/java资源文件夹,可以在项目上右键选择properties(首选项),然后点击java build path(java构建路径),在Librarys(库)下,编辑JRE System Library(JRE系统库),选择workspace default jre(工作空间缺省JRE)就可以了。

建立数据库

新建数据库hib_demo

新建t_dept , t_employee表,格式分别如下:

t_dept

img

t_employee

img

注解及数据库事务管理

注解及数据库事务管理代码清单

Dept.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.test.dept;
public class Dept {
private int deptId;
private String deptName;
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
}

DeptDao.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.test.dept;
import javax.annotation.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

/**
* dao实现,使用Spring对jdbc支持功能
* @author zhou
*/
@Repository
public class DeptDao {

@Resource
private JdbcTemplate jdbcTemplate;
// public void save(Dept dept){
// String sql = "insert into t_dept (deptName) values(?)";
// jdbcTemplate.update(sql,dept.getDeptName());
// }
public void save(String empvalue,String deptvalue){
String sql1 = "insert into t_employee (empName) values(?)";
jdbcTemplate.update(sql1,empvalue);
String sql2 = "insert into t_dept (deptName) values(?)";
jdbcTemplate.update(sql2,deptvalue);
}
}

TestJdbc.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.test.dept;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestJdbc {
// 部门dao
@Resource
private DeptDao deptDao;
/*
* 事务控制
*/
@Transactional(
readOnly = false, // 读写事务
timeout = -1, // 事务的超时时间不限制
//noRollbackFor = ArithmeticException.class, // 遇到数学异常不回滚
isolation = Isolation.DEFAULT, // 事务的隔离级别,数据库的默认
propagation = Propagation.REQUIRED // 事务的传播行为
)
@RequestMapping("save.do")
public void save(HttpServletRequest request){
System.out.println("成功");
String empValue=request.getParameter("empName");
String deptValue=request.getParameter("deptName");
//测试数据库事务,如有异常则回滚此数据库读写操作
deptDao.save(empValue,deptValue); // 保存员工名字和部门名字,如有异常则回滚此数据库读写操作
int i = 1/0; //设置异常
deptDao.save(empValue,deptValue); // 保存员工名字和部门名字
}
}

jsp页面

input.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="save.do">
员工名:<input type="text" name="empName">
部门名:<input type="text" name="deptName">
<input type="submit" value="提交">
</form>
</body>
</html>
save.jsp
1
2
3
4
5
6
7
8
9
10
11
12
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
传入数据库成功
</body>
</html>

项目进行SpringMvc配置

配置web.xml

配置web.xml,使其具有springmvc特性,主要配置DispatcherServlet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">

<welcome-file-list>input.jsp</welcome-file-list>
<!--配置DispatcherServlet表示,该工程将采用springmvc的方式。启动时也会默认在/WEB-INF目录下查找XXX-servlet.xml作为配置文件,XXX就是DispatcherServlet的名字-->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>

配置spring-servlet.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.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">
<!--该配置文件将配置两项重要的MVC特性:
1.HandlerMapping,负责为DispatcherServlet这个前端控制器的请求查找Controller;

2.ViewResolver,负责为DispatcherServlet查找Model And View的视图解析器。
-->
<!-- 1. 数据源对象: C3P0连接池 我用的是Mysql数据库,不同数据库此处配置有所不同-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql:///hib_demo"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<property name="initialPoolSize" value="3"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="2"></property>
</bean>

<!-- 2. JdbcTemplate工具类实例 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 事务管理器类 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 对包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能需要更改 -->
<context:component-scan base-package="com.test.dept"></context:component-scan>

<!-- 注解方式实现事务: 指定注解方式实现事务 -->
<tx:annotation-driven transaction-manager="txManager"/>

<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>

写完之后,项目结构如下:

img

测试结果

1
2
启动Tomcat,运行项目,进入input页面,如下图:

img

会弹出如下提示,是因为我们加了int i =1/0;这个异常:

img

最后去查找数据库发现,在异常之前进行的数据库也已回滚,并未产生读写,说明数据库事务管理成功!

spring使用JdbcTemplate实现MySQL存储过程

存储过程优点

存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。

一个存储过程是一个可编程的函数,它在数据库中创建并保存。它可以有SQL语句和一些特殊的控制结构组成。当希望在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟。

存储过程通常有以下优点:

1)存储过程增强了SQL语言的功能和灵活性。存储过程可以用流控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。

2)存储过程允许标准组件是编程。存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响.

3)存储过程能实现较快的执行速度。如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。

4)存储过程能过减少网络流量。针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织程存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大增加了网络流量并降低了网络负载。

5)存储过程可被作为一种安全机制来充分利用。系统管理员通过执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。

JdbcTemplate使用参考一下链接

1
2
3
4
http://www.cnblogs.com/lichenwei/p/3902294.html

http://lehsyh.iteye.com/blog/1579737

Spring使用JdbcTemplate调用Mysql存储过程:

概述

语法:

1
CREATE PROCEDURE sp_name ([ proc_parameter ]) [ characteristics..] routine_body

proc_parameter指定存储过程的参数列表,列表形式如下:

1
[IN|OUT|INOUT] param_name type

其中in表示输入参数,out表示输出参数,inout表示既可以输入也可以输出;param_name表示参数名称;type表示参数的类型,该类型可以是MYSQL数据库中的任意类型。

语法构建模板:

1
2
3
4
5
6
7
8
characteristic:
LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
routine_body:
Valid SQL procedure statement or statements

 LANGUAGE SQL :说明routine_body部分是由SQL语句组成的,当前系统支持的语言为SQL,SQL是LANGUAGE特性的唯一值

 [NOT] DETERMINISTIC :指明存储过程执行的结果是否正确。DETERMINISTIC 表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出。

[NOT] DETERMINISTIC 表示结果是不确定的,相同的输入可能得到不同的输出。如果没有指定任意一个值,默认为[NOT] DETERMINISTIC

 CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA:指明子程序使用SQL语句的限制。

CONTAINS SQL表明子程序包含SQL语句,但是不包含读写数据的语句;

NO SQL表明子程序不包含SQL语句;

READS SQL DATA:说明子程序包含读数据的语句;

MODIFIES SQL DATA表明子程序包含写数据的语句。

默认情况下,系统会指定为CONTAINS SQL

 SQL SECURITY { DEFINER | INVOKER } :指明谁有权限来执行。DEFINER 表示只有定义者才能执行

INVOKER 表示拥有权限的调用者可以执行。默认情况下,系统指定为DEFINER

COMMENT ‘string’ :注释信息,可以用来描述存储过程或函数

routine_body是SQL代码的内容,可以用BEGIN…END来表示SQL代码的开始和结束。

下面的语句创建一个查询t1表全部数据的存储过程

1
2
3
4
5
6
7
8
DROP PROCEDURE IF EXISTS Proc;
DELIMITER //
CREATE PROCEDURE Proc()
BEGIN
SELECT * FROM t3;
END//
DELIMITER ;
CALL Proc();

 注意:“DELIMITER //”语句的作用是将MYSQL的结束符设置为//,因为MYSQL默认的语句结束符为分号;,为了避免与存储过程*中SQL语句结束符相冲突,需要使用DELIMITER 改变存储过程的结束符,并以“END//”结束存储过程。

 存储过程定义完毕之后再使用DELIMITER ;恢复默认结束符。DELIMITER 也可以指定其他符号为结束符!!!!!!!!!!!

 注意:当使用DELIMITER命令时,应该避免使用反斜杠(\)字符,因为反斜杠是MYSQL的转义字符!!!

无返回值的存储过程调用

存储过程代码:
1
2
3
4
5
6
7
8
9
DROP PROCEDURE IF EXISTS testProcedure;

DELIMITER //
CREATE PROCEDURE testProcedure(IN empNameValue VARCHAR(20),IN deptNameValue VARCHAR(20))
BEGIN
INSERT INTO t_employee(empName) VALUES(empNameValue);
INSERT INTO t_dept(deptName) VALUES(deptNameValue);
END//
DELIMITER ;
JdbcTemplate调用该存储过程代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.test.procedure;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CallProcedure {
@Resource
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@RequestMapping("testProcedure.do")
public void testProcedure(){
final String empValue=request.getParameter("empName");
final String deptValue=request.getParameter("deptName");
this.jdbcTemplate.execute("call testProcedure('"+empValue+"','"+deptValue+"')");
}
}

有返回值的存储过程(非结果集)

存储过程代码:
1
2
3
4
5
6
7
8
9
10
11
DROP PROCEDURE IF EXISTS testProcedure;

DELIMITER //
CREATE PROCEDURE testProcedure(IN empNameValue VARCHAR(20),IN deptNameValue VARCHAR(20),OUT employeeName INT(11))
BEGIN
SELECT dept_id INTO employeeName FROM t_employee WHERE empId=1;
INSERT INTO t_employee(empName) VALUES(empNameValue);
INSERT INTO t_dept(deptName) VALUES(deptNameValue);

END//
DELIMITER ;
JdbcTemplate调用该存储过程代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.test.procedure;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class CallProcedure {
@Resource
public JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@RequestMapping("testProcedure.do")
public void testProcedure(HttpServletRequest request){
final String empValue=request.getParameter("empName");
final String deptValue=request.getParameter("deptName");
//传入从jsp获取的参数
//this.jdbcTemplate.execute("call testProcedure('"+empValue+"','"+deptValue+"')");
String empTable=(String) jdbcTemplate.execute(new CallableStatementCreator() {
public CallableStatement createCallableStatement(Connection con)
throws SQLException {
CallableStatement cs = con.prepareCall("call testProcedure(?,?,?)");
cs.setString(1, empValue);// 设置输入参数的值
cs.setString(2, deptValue);
cs.registerOutParameter(3,Types.VARCHAR);// 注册输出参数的类型
return cs;
}
}, new CallableStatementCallback<Object>() {

public Object doInCallableStatement(CallableStatement cs)
throws SQLException, DataAccessException {
cs.execute();
return cs.getString(3);// 获取输出参数的值
}
});
System.out.println(empTable);
}
}