6.事务 连接池

Posted 重庆刘亦菲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6.事务 连接池相关的知识,希望对你有一定的参考价值。

事务
  事务介绍:
    就是一件事情,操作要不全部成功,要不全部失败。
    mysql里的事务操作
      通过一个命令(show variables like ‘autocommit‘;)
        得到 autocommit=on;意思是事务 都自动提交
        每一条sql都是一个事务
      手动事务的操作:(☆)
        start transaction; 开始事务(不管是否自动提交)
        commit;提交事务
        rollback;事务回滚
      通过以下命令,可以设置事务为手动提交
        set autocommit=off;
        注意:一旦设置手动提交后,不要使用start transaction再开启事务了,这时开启的是新事务
    java里的事务操作
      Connection接口里面的方法:☆
        void setAutoCommit(boolean autoCommet):设置事务是否自动提交
        void commit():提交事务
        void rollback():事务回滚

        Savepoint setSavePoint():设置一个还原点
        void rollback(savepoint):还原到哪个还原点

public class AccountDemo {

    public static void main(String[] args)  {
        
        //aaa->bbb转钱
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        Savepoint p=null;
        
        
        
        try {
            conn=JDBCUtils.getConnection();
            
            //手动开启事务
            conn.setAutoCommit(false);
            
            //先给a减钱
            String sql="update account set money =money-? where name=?";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "500");
            ps.setString(2, "aaa");
            int i=ps.executeUpdate();
            System.out.println(i);
            
            //设置还原点
            p=conn.setSavepoint();
            
            /*if(i==1){
                throw new RuntimeException();
            }*/
            
            //给b加钱
            sql="update account set money =money+? where name=?";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "500");
            ps.setString(2, "bbb");
            i=ps.executeUpdate();
            System.out.println(i);
            
        } catch (Exception e) {
            e.printStackTrace();
            //回滚事务
            try {
                conn.rollback(p);
            } catch (SQLException e1) {
                
                e1.printStackTrace();
            }
        }finally{
            //提交事务
            try {
                conn.commit();
            } catch (SQLException e) {
                
                e.printStackTrace();
            }
            
            JDBCUtils.closeResources(conn, ps, rs);
        }
        
    }

}

 


  事务的特性:(☆)
    ACID
    原子性:atomicity 要么全部成功,要么全部失败
    一致性:consistency 事务执行之后,数据库状态与其它业务规则保持一致。例如:转账,总钱数不变
    隔离性:isolation 在并发操作中,不同事务之间应该隔离开来,使每个并发中的事务不会相互干扰。
    持久性:durability 一旦事务提交或回滚后,必须持久化到数据库中
  隔离性:
    若不考虑隔离性,会出现的问题:
      脏读:读取到别的事务没有提交的数据
      不可重复读:在一个事务中,两次查询的结果不一致(内容 update)
      虚读(幻读):在一个事务中,两次查询的结果不一致(条数,针对insert delete操作)
    数据库的隔离级别:
      read uncommitted:读未提交,最低的级别,上面的情况都可以发生
      read committed:读已提交,可以避免脏读
      repeatable read:可重复读,可以避免不可重复读
      serializable:串行化,最高的等级,可以避免所有问题。
  演示几种问题:
    设置数据库的隔离级别:
      set session transactioin isolation level 级别;
    查看当前的隔离级别:
      select @@tx_isolation;
      mysql默认的隔离级别:repeatable read☆
      oracle扩展的隔离级别:read committed☆
  安全性:
    serializable>repeatable read>read committed>read uncommitted
  效率:反之


  案例:
    转账案例
    解决service层需要传入connection参数:
    Map<Thread,Connection> map

    第一次开始事务的时候,先获取map.get(Thread.currentThread()) == ThreadLocal.get()
    获取一个connection,开启事务,最后map.put(Thread.currentThread(),connection) == ThreadLocal.set()
    在dao层可以直接使用,map.get(Thread.currentThread())就可以获取绑定的链接

  执行的流程:
    account.jsp:接收用户信息
    accountServlet:接收参数,调用service,页面的跳转
    accountService:
      1.开启事务
        conn.startTransaction() ThreadLocal作用:将当前的链接和当前的线程绑定起来
      2.开始转账
      3.一旦出现异常 获取当前线程绑定的链接调用rollBack()
      4.最后,提交事务,获取当前线程绑定的链接调用commit(),然后关闭链接,最后和当前线程解绑
    accountDao:
      转入
      转出

account.jsp

<%@ 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>
	<h1><font color="red">${msg }</font></h1>
	<form method="post" action="${pageContext.request.contextPath }/account">
		<table border="1">
			<tr>
				<td>汇款人:</td>
				<td><input type="text" name="fromuser"></td>
			</tr>
			<tr>
				<td>收款人:</td>
				<td><input type="text" name="touser"></td>
			</tr>
			<tr>
				<td>转账金额:</td>
				<td><input type="text" name="money"></td>
			</tr>
			<tr>
				<td colspan="2"><input type="submit"></td>
			</tr>
		</table>
	 </form>
</body>
</html>

JDBCUtil:

public class JDBCUtils_ {

	static final String DRIVERCLASSNAME;
    static final String URL;
    static final String USER;
    static final String PASSWORD;
    
    static{
    	/**
		 * ResourceBundle:用于加载properties文件
		 * 	 ResourceBundle bundle=ResourceBundle.getBundle(文件名称);
		 *   通过bundle的getString(key)就可以获取指定value
		 *    String url=bundle.getString("url");
		 */
    	ResourceBundle bundle=ResourceBundle.getBundle("jdbc"); //不需要后缀名
    	DRIVERCLASSNAME=bundle.getString("driverClassName");
    	URL=bundle.getString("url");
    	USER=bundle.getString("user");
    	PASSWORD=bundle.getString("password");
    }
    
    static{
    	
    	try {
			Class.forName(DRIVERCLASSNAME);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
    
  /**
   * 获取链接
   * @return 链接
   * @throws SQLException
   */
    public static Connection getConnection() throws SQLException{
    	//第一次开启事务,先获取 
    	Connection conn=tl.get();
    	if(conn==null){
    		//创建一个
    		conn= DriverManager.getConnection(URL,USER,PASSWORD);
    		//和当前线程绑定
    		tl.set(conn);

    	}
    	return conn;
    }
    
    /**
     * 开启事务
     * @throws SQLException
     */
    public static void startTransaction() throws SQLException{
    	getConnection().setAutoCommit(false);
    }
    
    /**
     * 事务回滚
     * @throws SQLException
     */
    public static void rooBack() throws SQLException{
    	getConnection().rollback();
    }
    
    /**
     * 事务提交及关闭
     * @throws SQLException
     */
    public static void coommitAndClose() throws SQLException{
    	Connection conn=getConnection();
    	conn.commit();
    	conn.close();
    	tl.remove();//将链接移除
    }
    
    /**
     * 做增删改的时候调用
     * @param conn
     * @param st
     */
    public static void closeResources(Connection conn,Statement st){
    	
    	if(st!=null){
    		try {
				st.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	if(conn!=null){
    		try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
    
    /**
     * 做查询时调用
     * @param conn
     * @param st
     * @param rs
     */
    public static void closeResources(Connection conn,Statement st,ResultSet rs){
    	closeResources(st,rs);
    	
    	if(conn!=null){
    		try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
    
    
    public static void closeResources(Statement st,ResultSet rs){
    	if(rs!=null){
    		try {
				rs.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	if(st!=null){
    		try {
				st.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }

}

AccountServlet:

public class AccountServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		/*
		 * 接收参数
		 * 调用service
		 */
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//0.设置编码
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");  
		
		//1.接收参数
		String fromUser=request.getParameter("fromuser");
		String toUser=request.getParameter("touser");
		String money=request.getParameter("money");
		
		
		//2.调用service
		AccountService accountService=new AccountService();
		try {
			accountService.account(fromUser, toUser, money);
		} catch (MyException e) {
			e.printStackTrace();
			//添加消息,页面跳转
			request.setAttribute("msg", e.getMessage());
			request.getRequestDispatcher("/account.jsp").forward(request, response);
			return;
		}
				
		//3.页面跳转
		response.getWriter().print("转账成功");
	}
}

AccountService:

public class AccountService_ {
	
	public void  account(String fromUser,String toUser,String money){
		//开始事务
		try {
			JDBCUtils_.startTransaction();
			
			AccountDao_ accountDao=new AccountDao_();
			//出
			accountDao.accountOut( fromUser, money);
			
			//如
			accountDao.accountIn(toUser,money);
			
			
		} catch (SQLException e) {
			
			e.printStackTrace();
			
			//回滚
			try {
				JDBCUtils_.rooBack();
			} catch (SQLException e1) {
				
				e1.printStackTrace();
			}
		} catch (MyException e) {
			
			e.printStackTrace();
		}finally{
			//提交
			try {
				JDBCUtils_.coommitAndClose();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

AccountDao:

public class AccountDao_ {

	public void accountOut(String fromUser, String money) throws MyException {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		try {
			conn=JDBCUtils_.getConnection();
			String sql="upate account set money=money-? where name=?";
			ps.setString(1, money);
			ps.setString(2, fromUser);
			
			int i=ps.executeUpdate();
			if(i!=1){
				throw new MyException("转出失败");
			}
		} catch (SQLException e) {
			
			e.printStackTrace();
			try {
				JDBCUtils_.rooBack();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
		}finally{
			try {
				JDBCUtils_.coommitAndClose();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void accountIn(String toUser, String money) throws MyException, SQLException {
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		try {
			conn=JDBCUtils_.getConnection();
			String sql="upate account set money=money+? where name=?";
			ps.setString(1, money);
			ps.setString(2, toUser);
			
			int i=ps.executeUpdate();
			if(i!=1){
				throw new MyException("转入失败");
			}
		} catch (SQLException e) {
			
			e.printStackTrace();
			try {
				JDBCUtils_.rooBack();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally{
			JDBCUtils_.coommitAndClose();
		}
		
	}

}

Exception:

public class MyException extends Exception{

	public MyException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

	public MyException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public MyException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public MyException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}
}

  

 

连接池:
  连接池的优点:
    1.提高了链接的复用性
    2.节省了创建链接、销毁链接的时间,提高了性能
  规范:
    连接池都应该是DataSource的实现,datasource是一个规范,javax.sql包的一个接口
  获取链接:
    getConnection()
  关闭的时候:
    conn.close()
  常见的连接池:
    dbcp(理解):apache组织的
    c3p0(☆):c3p0
    tomcat内置的连接池(了解)
  dbcp的使用:
    1.导入jar包 commons-dbcp-1.4.jar(核心) 和commons-pool-1.5.6.jar(依赖)
    2.编写代码(两种方式)
    第一种方式:源码中配置

    第二种方式:配置文件

dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day14
username=root
password=moujinling321


DBCPDemo
public class DBCPDemo {
    public static void main(String args[]) throws Exception {
        //method1();
        method2();
    }
    
    private static void method2() throws Exception {
        /*
         * 方式二:配置文件
         */
        BasicDataSourceFactory factory=new BasicDataSourceFactory();
        Properties p=new Properties();
        p.load(new FileInputStream("src/dbcp.properties"));
        
        DataSource ds=factory.createDataSource(p); 
        
        Connection conn=ds.getConnection();
        String sql="select * from account limit 1";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
        
    }

    private static void method1() throws SQLException{
        /*
         * 方式一:源码中配置
         */
        BasicDataSource ds=new BasicDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/day14");
        ds.setUsername("root");
        ds.setPassword("moujinling321");
        
        Connection conn=ds.getConnection();
        String sql="select * from account";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
    }
}

  c3p0的使用:
    项目中使用
    自动回收空闲的链接
    使用步骤:
      1.导入jar包 c3p0-0.9.1.2.jar
      2.编码
      方式1:编码中编写配置(理解)
      方式2:配置文件

c3p0.properties
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/day14
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.user=root
c3p0.password=moujinling321


C3P0Demo
public class C3P0Demo {
    public static void main(String[] args) throws PropertyVetoException, SQLException {
        //method1();
        method2();
    }

    //第二种方式:配置文件(自动查找)
    private static void method2() throws SQLException {
        
        ComboPooledDataSource ds= new ComboPooledDataSource();
        
        Connection conn=ds.getConnection();
        String sql="select * from account limit 1";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
        
    }

    //第一种方式:源码中配置
    private static void method1() throws PropertyVetoException, SQLException {
        ComboPooledDataSource ds= new ComboPooledDataSource();
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/day14");
        ds.setUser("root");
        ds.setPassword("moujinling321");
        
        Connection conn=ds.getConnection();
        String sql="select * from account";
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        ps=conn.prepareStatement(sql);
        rs=ps.executeQuery();
        while(rs.next()){
            System.out.println(rs.getString(1)+":"+rs.getString(2));
        }
        rs.close();
        ps.close();
        conn.close();
    }
}

 

注册要求:用户名相同不能注册

regist.jsp

<%@ 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>
		<title>bookStore 商城-商品信息展示</title>
	</head>
	<body>
		<!-- head 一行两列的表格-->
		<%@include file="/public/head.jsp" %>
		
		<!-- menu 一行一列的表格-->
		<%@include file="/public/menu.jsp" %>
		
		<!-- search 一行一列的表格 -->
		<div id="search">
			<table width="100%" bgcolor="#B6B684">
				<tr align="right">
					<td>
						search
						<input type="text"/>
						<input type="button" value="搜索"/>      
					</td>
				</tr>
			</table>
		</div>
		
		<!-- content -->
		<div id="content">
			<form action="${pageContext.request.contextPath}/regist" method="post">
				<table align="center" bgcolor="#FFFFF4" width="60%">
					<tr>
						<td>
							<h1>新会员注册<font color="red">${regist_msg }</font></h1>
							<table align="center">
								<tr>
									<td align="right" >会员邮箱:</td>
									<td>
										<input type="text" name="email"/>
									</td>
									<td align="left">
										<font color="#ff0000">${map.email_msg }</font>
									</td>
								</tr>
								<tr>
									<td align="right">会员名:</td>
									<td>
										<input type="text" name="username" class="txtinput"/>
									</td>
									<td align="left">
										<font color="#ff0000"></font>
									</td>
								</tr>
								<tr>
									<td align="right">密码:</td>
									<td>
										<input type="password" name="password" class="txtinput"/>
									</td>
									<td align="left">
										<font color="#ff0000"></font>
									</td>
								</tr>
								<tr>
									<td align="right">重复密码:</td>
									<td>
										<input type="text" name="repassword"/>
									</td>
								</tr>
								<tr>
									<td align="right">性别:</td>
									<td>
										<input type="radio" name="sex" value="男"/>男
										<input type="radio" name="sex" value="女"/>女
									</td>
									<td></td>
								</tr>
								<tr>
									<td align="right">联系电话:</td>
									<td>
										<input type="text" name="telephone"/>
									</td>
								</tr>
								<tr>
									<td align="right">个人介绍:</td>
									<td>
										<input type="textarea" name="introduce"/>
									</td>
								</tr>
							</table>
							<h1>注册校验</h1>
							<table align="center" width="80%" cellspacing="2">
								<tr>
									<td align="right">输入校验码:</td>
									<td>
										<input type="text" name="checkcode" class="txtinput"/>
									</td>
									<td>${requestScope["code.msg"] }</td> <!-- code.msg,单独不可以写进去,.表示get。用域对象表示出来 -->
								</tr>
								<tr>
									<td> </td>
									<td colspan="2">
										<img src="${pageContext.request.contextPath }/code" id="imgId" alt="验证码" class="txtinput" style="height:30px"/>
										<a href="javascript:void(0)" onclick="changeCode()">看不清?换一张</a>
										<!-- 表示这个链接不做跳转动作,执行onClick事件。 -->
									</td>
								</tr>
								<tr>
									<td align="center" colspan="3">
										<input value="同意并提交" style="background:orange;height:30px;width:100px;text-align:center;" type="submit"/>
									</td>
								</tr>
							</table>
						</td>
					</tr>
				</table>
			</form>
			
		</div>
		
		<!-- foot 两行两列的表格-->
		<div id="foot">
			<table width="100%" bgcolor="#EFEEDC">
				<tr>
					<td rowspan="2" align="center">
						<img src="images/case1/logo.png" alt="图书商城"/>
					</td>
					<td>CONTACT US</td>
				</tr>
				<tr>
					<td>
						copyright 2008&copyrightBookStore All Rights RESERVED
					</td>
				</tr>
			</table>
		</div>
		
		<table width="100%">
			<tr>
				<td></td>
			</tr>
		</table>
	</body>
<script type="text/javascript">
	function changeCode(){
		var imgObj=document.getElementById("imgId");
		imgObj.src="${pageContext.request.contextPath}/code?i="+Math.random();
	}
</script>

</html>

  RegistServlet

package web.servlet;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;

import domain.User;
import exception.UserRegistException;
import service.UserService;

public class RegistServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		request.setCharacterEncoding("utf-8");
		
		/*
		 * 作用:首先判断验证码
		 * 	若验证码不一致,返回错误信息(regist.jsp) 提示信息(验证码错误) request
		 * 	验证码一致,封装参数,调用userservice
		 */
		
		//1.获取验证码 
		//1.1获取页面上验证码
		String code=request.getParameter("checkcode");
		
		//1.2获取session域中的验证码
		String sessionCode=(String) request.getSession().getAttribute("session_code");
		request.getSession().removeAttribute("session_code"); //验证码一次性
		
		//2.判断验证码
		//输入验证码不正确
		if(!sessionCode.equalsIgnoreCase(code)){
			//加入错误信息,页面跳转
			request.setAttribute("code.msg", "验证码输入错误");
			request.getRequestDispatcher("/regist.jsp").forward(request,response);
			return;
		}
		
		//3.获取参数
		User user=new User();
		try {
			BeanUtils.populate(user, request.getParameterMap());
		} catch (IllegalAccessException | InvocationTargetException e) {
			
			e.printStackTrace();
		}
		//3.1数据校验
		//验证邮件
		Map<String,String> map=user.validate();
		if(map!=null && map.size()>0){
			//有错误信息
			request.setAttribute("map", map);
			request.getRequestDispatcher("/regist.jsp").forward(request, response);
			return;
		}
		
		//4.调用userservice
		UserService userService=new UserService();
		//可能抛自定义异常
		try {
			userService.regist(user);
		} catch (UserRegistException e) {
			e.printStackTrace();
			//有异常,添加错误信息,跳转到注册页面
			request.setAttribute("regist_msg", e.getMessage());
			request.getRequestDispatcher("/regist.jsp").forward(request, response);
		}
		
		//5.页面跳转,提示信息
		//5.1将user放到session中
		request.getSession().setAttribute("user", user);
		
		//5.2提示信息 页面跳转
		response.setHeader("refresh", "3;url="+request.getContextPath()+"/success.jsp");
		response.getWriter().print("注册成功,3秒之后跳转到首页!");
		
	}
}

  UserService

public class UserService {
	UserDaoImpl userDao=new UserDaoImpl();
	/**
	 * 用户注册
	 * @param user 用户信息
	 * @throws UserRegistException 
	 */
	public void regist(User user) throws UserRegistException  {
		
		try {
			//开启事务
			DataSourceUtils.startTransaction();
			
			/*
			 * 首先判断数据库中有没有同名的
			 * 	若有,返回true,不能注册,提示信息
			 * 	若无,可以添加
			 */
			boolean flag=userDao.findUserByUsername(user);
			if(!flag){//flag=false
				
				//调用userdao的adduser方法
				userDao.addUser(user);
			}else{
				throw new UserRegistException("该用户名已被占用");
			}
		} catch (SQLException e) {
			
			e.printStackTrace();
			
			try {
				DataSourceUtils.rollBack();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			throw new UserRegistException("网络异常!!");
		}finally{
			//提交事务
			try {
				DataSourceUtils.commitAndClose();
			} catch (SQLException e) {
				
				e.printStackTrace();
			}
		}

	}

}

  UserDao

public class UserDaoImpl implements UserDao{
	/**
	 * 添加用户
	 * @param user 用户信息
	 * @throws UserRegistException 
	 * @throws SQLException 
	 */
	public void addUser(User user) throws UserRegistException {
		//使用JDBC操作数据库
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		try {
			conn=DataSourceUtils.getConnection();
			
			//编写sql
			//username,password,sex,telephone,email,introduce
			String sql="insert into user values(null,?,?,?,?,?,?)";
			
			//创建语句执行者
			ps=conn.prepareStatement(sql);
			//设置参数
			ps.setString(1, user.getUsername());
			ps.setString(2, user.getPassword());
			ps.setString(3, user.getSex());
			ps.setString(4, user.getTelephone());
			ps.setString(5, user.getEmail());
			ps.setString(6, user.getIntroduce());
			//执行sql
			int i=ps.executeUpdate();
			if(i==0){
				throw new UserRegistException("注册失败");
			}
			//处理结果
			System.out.println(i);
		} catch (SQLException e) {
			// 数据库异常
			e.printStackTrace();
			throw new UserRegistException("网络异常,请稍后再试");
		}finally{
			//释放资源
			DataSourceUtils.closeResources(ps, rs);
		}
	}

	/**
	 * 通过用户名查找用户
	 * 	若存在返回true
	 * 	若不存在返回false
	 */
	public boolean findUserByUsername(User user) {
		
		//使用JDBC操作数据库
		Connection conn=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
				
		try {
			conn=DataSourceUtils.getConnection();
			String sql="select * from user where username=? limit 1";
			ps=conn.prepareStatement(sql);
			ps.setString(1, user.getUsername());
			rs=ps.executeQuery();
			return rs.next();
		} catch (SQLException e) {
		
			e.printStackTrace();
		}finally{
			DataSourceUtils.closeResources(ps, rs);
		}
		return false;
	}
}

  User

public class User {
	private Integer id;
	private String email;
	private String username;
	private String password;
	private String sex;
	private String introduce;
	private String telephone;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public String getIntroduce() {
		return introduce;
	}
	public void setIntroduce(String introduce) {
		this.introduce = introduce;
	}
	public String getTelephone() {
		return telephone;
	}
	public void setTelephone(String telephone) {
		this.telephone = telephone;
	}
	public User(Integer id, String email, String username, String password, String sex, String introduce,
			String telephone) {
		super();
		this.id = id;
		this.email = email;
		this.username = username;
		this.password = password;
		this.sex = sex;
		this.introduce = introduce;
		this.telephone = telephone;
	}
	public User() {
		super();
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", email=" + email + ", username=" + username + ", password=" + password + ", sex="
				+ sex + ", introduce=" + introduce + ", telephone=" + telephone + "]";
	}
	public Map<String, String> validate() {
		//创建Map
		Map<String,String> map=new HashMap();
		
		//验证邮箱
		/*
		 * 首先验证邮箱是否为空
		 * 	若为空,提示邮箱不能为空
		 * 	若不为空,继续验证邮箱是否符合格式
		 * 		若不符合,提示邮箱格式不争取
		 * 		
		 */
		if(isNull(email)){
			map.put("email_msg", "邮箱不能为空");
		}else if(!checkEmail(email)){
			map.put("email_msg", "邮箱格式不合法");
		}
		
		return map;
	}
	
	/**
	 * 判断邮箱格式
	 * 	若符合格式,返回true
	 * 	若不符合格式,返回false
	 * @param value
	 * @return bolean
	 */
	private boolean checkEmail(String value) {
		if(value==null){
			return false;
		}
		//[email protected]
		String reg="^\\[email protected]\\w+(\\.\\w+)+$";
		return value.matches(reg);
	}
	/**
	 * 验证是否为空
	 * 	若为空返回Null
	 * 	若不为空返回false
	 * @param value
	 * @return boolean
	 */
	private boolean isNull(String value) {
		//^\s*&
		if(value==null){
			return true;
		}
		return value.matches("^\\s*$");
	}
	
}

  

以上是关于6.事务 连接池的主要内容,如果未能解决你的问题,请参考以下文章

Jooq 事务:如果事务中抛出异常,则连接不会释放到池中

Java 微服务 乐优网络商城 day02 源代码 SpringBoot 实战开发 整合JDBC和事务(数据库连接池)

JavaWeb之事务&数据库连接池

在 Tomcat7 中使用 JDBC 连接池进行事务处理

Mybatis框架第二篇

片段事务中的实例化错误