1 . 今天学习了事务,来看一下jdbc是如何操作事务的.(最基本的)
2 . 以转账为例:
- 创建数据库和表
- 创建一个web工程,连接数据库,添加数据库驱动mysql;
- 转账页面 transformAccount.jsp (A转账到B 输入1000元) 按钮:转账 提交表单
- 转账servlet(TransformServlet)
a.获取表单数据
b.调用service层处理转账业务功能 (转账业务功能需要调用dao层)
c.根据业务结果决定页面如何显示
3 . 要清除,jdbc是用connection来进行操作事务的.
4 .home页面
<%@ 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="TransServlet" method="post">
转账人: <input type="text" name="fromname"/><br>
收账人: <input type="text" name="toname"/><br>
转账金额: <input type="text" name="money"/><br>
<input type="submit" value="转账"/>
</form>
</body>
</html>
5 . servlet层
package com.lm.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lm.service.UserService;
import com.lm.service.impl.UserServiceImpl;
/**
* 分发转向
*/
public class TransServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1 . 获取请求参数
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String fromname = request.getParameter("fromname");
String toname = request.getParameter("toname");
String money = request.getParameter("money");
System.out.println(fromname+" "+toname+" "+money);
// 2 . 处理请求参数
UserService userService = new UserServiceImpl();
double money1 = Double.parseDouble(money);
boolean flag = userService.trans(fromname, toname, money1);
if(flag) {
response.sendRedirect("success.jsp");
}else {
request.setAttribute("trans_error_msg", "转账失败");
request.getRequestDispatcher("home.jsp").forward(request,response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
注意处理请求参数的那块,
UserService userService = new UserServiceImpl();
UserService 这是个接口,里面定义了UserServiceImpl类的方法,就是为了保证数据安全.
6 . service层
package com.lm.service.impl;
import java.sql.Connection;
import java.sql.SQLException;
import com.lm.dao.UserDao;
import com.lm.dao.impl.UserDaoImpl;
import com.lm.service.UserService;
import com.lm.utils.DBUtils;
public class UserServiceImpl implements UserService{
@Override
public boolean trans(String fromname, String toname, double money) {
boolean flag = false;
Connection connection = DBUtils.getConnection();
UserDao userDao = new UserDaoImpl(connection);
try {
// 1. 开启事务
connection.setAutoCommit(false);
double fromMoney = userDao.queryMoneyByUser(fromname);
double toMoney = userDao.queryMoneyByUser(toname);
//先设置两个人转账之后的金额
fromMoney = fromMoney-money;
toMoney = toMoney + money;
//更新每个用户的钱 如果更新不成功会抛出异常 之后执行catch
//向上转型 子类创建的对象赋值给父类
//这里的userDao是一个对象,给这个对象初始化了connection属性.
//所以在userDao调用queryMoneyByUser和queryMoneyByUser方法的时候,
//在dao层的connection.prepareStatement(sql)时是connection时没有定义的,
//在这实际上是this.connection.prepareStatement(sql),也就是当前对象的connection调用prepareStatement方法
int row1 = userDao.updateMoneyByUser(fromname, fromMoney);
int row2 = userDao.updateMoneyByUser(toname, toMoney);
//判断是不是都更新成功
if(row1>0 && row2>0) {
System.out.println("转账成功");
flag = true;
}else {
System.err.println("转账失败");
flag = false;
}
connection.commit();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("错误信息:"+e.getMessage());
flag = false;
// 3 . 事务回滚
try {
connection.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
return flag;
}
}
7 . dao层
package com.lm.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.management.loading.PrivateClassLoader;
import com.lm.dao.UserDao;
import com.sun.corba.se.spi.orbutil.fsm.Guard.Result;
public class UserDaoImpl implements UserDao{
//connection 属性
private Connection connection;
public UserDaoImpl(Connection connection) {
this.connection = connection;
}
@Override
public double queryMoneyByUser(String Username) throws SQLException {
String sql="select * from user where name =?";
//下面等号右边相当于this.connection.prepareStatement(sql);
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, Username);
ResultSet resultSet = preparedStatement.executeQuery();
double money = 0;
while(resultSet.next()) {
money = resultSet.getDouble("money");
}
return money;
}
@Override
public int updateMoneyByUser(String Username, double money) throws SQLException {
String sql="update user set money = ? where name = ? ";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(2, Username);
preparedStatement.setDouble(1, money);
int row = preparedStatement.executeUpdate();
return row;
}
}
注意,dao层是有connection属性的.
这个例子用到了自定义异常,还用到了接口和实现类,为了数据的安全,下面给出UserDao的接口,
package com.lm.dao;
import java.sql.SQLException;
public interface UserDao {
//查询指定用户金钱
public double queryMoneyByUser(String Username) throws SQLException;
//更新指定用户金钱
public int updateMoneyByUser(String Username,double money) throws SQLException;
}
UserDaoImpl的方法throws异常的话,service会捕获异常,connection.commit();不会执行到,从而会执行catch进行事务回滚connection.rollback();
总结:通过这个例子,要学会自己在哪抛出异常,在哪捕获异常,还有接口的使用.