web day19 Service层处理事务(利用ThreadLocal),TxQueryRunner小工具,单表练习(增删改查操作)

Service事务

 

DAO中不是处理事务的地方,因为DAO中的每个方法都是对数据库的一次操作

在Service中不应该出现Connection,它应该只在DAO中出现,

因为它是JDBC的东西,JDBC的东西是用来连接数据库的

 

 

修改JdbcUtils

 

我们把对事务的开启和关闭放到JdbcUtils中,在Service中调用JdbcUtils的方法来完成事务的处理,

但在Service中就不会再出现Connection这一“禁忌”了。

 

 

代码

public class JdbcUtils {
	// 配置文件的默认配置!要求你必须给出c3p0-config.xml!!!
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	// 它是事务专用连接!
	private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
	
	/**
	 * 使用连接池返回一个连接对象
	 * @return
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException {
		Connection con = tl.get();
		// 当con不等于null,说明已经调用过beginTransaction(),表示开启了事务!
		if(con != null) return con;
		return dataSource.getConnection();
	}
	
	/**
	 * 返回连接池对象!
	 * @return
	 */
	public static DataSource getDataSource() {
		return dataSource;
	}
	
	/**
	 * 开启事务
	 * 1. 获取一个Connection,设置它的setAutoComnmit(false)
	 * 2. 还要保证dao中使用的连接是我们刚刚创建的!
	 * --------------
	 * 1. 创建一个Connection,设置为手动提交
	 * 2. 把这个Connection给dao用!
	 * 3. 还要让commitTransaction或rollbackTransaction可以获取到!
	 * @throws SQLException 
	 */
	public static void beginTransaction() throws SQLException {
		Connection con = tl.get();
		if(con != null) throw new SQLException("已经开启了事务,就不要重复开启了!");
		/*
		 * 1. 给con赋值!
		 * 2. 给con设置为手动提交!
		 */
		con = getConnection();//给con赋值,表示事务已经开始了
		con.setAutoCommit(false);
		
		tl.set(con);//把当前线程的连接保存起来!
	}
	
	/**
	 * 提交事务
	 * 1. 获取beginTransaction提供的Connection,然后调用commit方法
	 * @throws SQLException 
	 */
	public static void commitTransaction() throws SQLException {
		Connection con = tl.get();//获取当前线程的专用连接
		if(con == null) throw new SQLException("还没有开启事务,不能提交!");
		/*
		 * 1. 直接使用con.commit()
		 */
		con.commit();
		con.close();
		// 把它设置为null,表示事务已经结束了!下次再去调用getConnection()返回的就不是con了
		tl.remove();//从tl中移除连接
	}
	
	/**
	 * 提交事务
	 * 1. 获取beginTransaction提供的Connection,然后调用rollback方法
	 * @throws SQLException 
	 */
	public static void rollbackTransaction() throws SQLException {
		Connection con = tl.get();
		if(con == null) throw new SQLException("还没有开启事务,不能回滚!");
		/*
		 * 1. 直接使用con.rollback()
		 */
		con.rollback();
		con.close();
		tl.remove();
	}
	
	/**
	 * 释放连接 
	 * @param connection
	 * @throws SQLException 
	 */
	public static void releaseConnection(Connection connection) throws SQLException {
		Connection con = tl.get();
		/*
		 * 判断它是不是事务专用,如果是,就不关闭!
		 * 如果不是事务专用,那么就要关闭!
		 */
		// 如果con == null,说明现在没有事务,那么connection一定不是事务专用的!
		if(con == null) connection.close();
		// 如果con != null,说明有事务,那么需要判断参数连接是否与con相等,若不等,说明参数连接不是事务专用连接
		if(con != connection) connection.close();
	}



TxQueryRunner小工具


自动处理连接的关闭,无需再传递连接参数,自动传递

通过继承QueryRunner类 ,同时重写了所有没有接连参数传递的方法(重写都加上了)


代码

/**
 * 这个类中的方法,自己来处理连接的问题
 * 无需外界传递! 
 * 怎么处理的呢?
 *   通过JdbcUtils.getConnection()得到连接!有可能是事务连接,也可能是普通的连接!
 *   JdbcUtils.releaseConnection()完成对连接的释放!如果是普通连接,关闭之!
 * @author cxf
 *
 */
public class TxQueryRunner extends QueryRunner {
	@Override
	public int[] batch(String sql, Object[][] params) throws SQLException {
		/*
		 * 1. 得到连接
		 * 2. 执行父类方法,传递连接对象
		 * 3. 释放连接
		 * 4. 返回值
		 */
		Connection con = JdbcUtils.getConnection();
		int[] result = super.batch(con, sql, params);
		JdbcUtils.releaseConnection(con);
		return result;
	}

	@Override
	public <T> T query(String sql, Object param, ResultSetHandler<T> rsh)
			throws SQLException {
		Connection con = JdbcUtils.getConnection();
		T result = super.query(con, sql, param, rsh);
		JdbcUtils.releaseConnection(con);
		return result;
	}

	@Override
	public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh)
			throws SQLException {
		Connection con = JdbcUtils.getConnection();
		T result = super.query(con, sql, params, rsh);
		JdbcUtils.releaseConnection(con);
		return result;
	}

	@Override
	public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
			throws SQLException {
		Connection con = JdbcUtils.getConnection();
		T result = super.query(con, sql, rsh, params);
		JdbcUtils.releaseConnection(con);
		return result;
	}

	@Override
	public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
		Connection con = JdbcUtils.getConnection();
		T result = super.query(con, sql, rsh);
		JdbcUtils.releaseConnection(con);
		return result;
	}

	@Override
	public int update(String sql) throws SQLException {
		Connection con = JdbcUtils.getConnection();
		int result = super.update(con, sql);
		JdbcUtils.releaseConnection(con);
		return result;
	}

	@Override
	public int update(String sql, Object param) throws SQLException {
		Connection con = JdbcUtils.getConnection();
		int result = super.update(con, sql, param);
		JdbcUtils.releaseConnection(con);
		return result;
	}

	@Override
	public int update(String sql, Object... params) throws SQLException {
		Connection con = JdbcUtils.getConnection();
		int result = super.update(con, sql, params);
		JdbcUtils.releaseConnection(con);
		return result;
	}
}



单表的增删改查练习


添加客户分析

 

add.jsp→CustomerServlet#add()显示添加成功!

 

代码的实现

 DAO#addCustomer(Customer c):

       给出sql语句的模板

       把参数c转换成一个Object[]

       调用QueryRunner的update方法。

 Service#addCustomer(Customer c):

       直接调用dao的addCustomer(c);

 
查看客户分析

查看所有用户信息列表

top.jsp→CustomerServlet#findAll()→list.jsp


  DAO:

     sql = “select * from t_customer”;

     qr.query(),需要把结果集映射成List<Customer>,所以使用BeanListHandler

 

条件查询

query.jsp  CustomerServlet#query()  list.jsp

修改客户

 

id查询流程



编辑流程



删除客户

 

1.当用户在list.jsp页面中点击“删除”时,通过CustomerServlet的delPre方法来处理:

2.获取cid;

3.通过cid获取Customer对象;

4.把Customer对象保存到request中

5.转发到del.jsp

2.1当用户在del.jsp页面点击删除时,通过Customer的del方法来处理:

2.2获取cid

2.3通过CustomerService来完成删除

3.向页面输出“删除成功”

 

 

代码

web层
/**
 * Web层
 * @author cxf
 *
 */
public class CustomerServlet extends BaseServlet {
	private CustomerService customerService = new CustomerService();
	
	/**
	 * 添加客户
	 */
	public String add(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 封装表单数据到Customer对象
		 * 2. 补全:cid,使用uuid
		 * 3. 使用service方法完成添加工作
		 * 4. 向request域中保存成功信息
		 * 5. 转发到msg.jsp
		 */
		Customer c = CommonUtils.toBean(request.getParameterMap(), Customer.class);
		c.setCid(CommonUtils.uuid());
		customerService.add(c);
		request.setAttribute("msg", "恭喜,添加客户成功!");
		return "f:/msg.jsp";
	}
	
	/**
	 * 查询所有
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public String findAll(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 调用service得到所有客户
		 * 2. 保存到request域
		 * 3. 转发到list.jsp
		 */
		request.setAttribute("cstmList", customerService.findAll());
		return "f:/list.jsp";
	}
	
	/**
	 * 编辑之前的加载工作
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public String preEdit(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 获取cid
		 * 2. 使用cid来调用service方法,得到Customer对象
		 * 3. 把Customer保存到request域中
		 * 4. 转发到edit.jsp显示在表单中
		 */
		String cid = request.getParameter("cid");
		Customer cstm = customerService.load(cid);
		request.setAttribute("cstm", cstm);
		return "f:/edit.jsp";
	}
	
	/**
	 * 编辑方法
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public String edit(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 封装表单数据到Customer对象中
		 * 2. 调用service方法完成修改
		 * 3. 保存成功信息到request域
		 * 4. 转发到msg.jsp显示成功信息
		 */
		// 已经封装了cid到Customer对象中
		Customer c = CommonUtils.toBean(request.getParameterMap(), Customer.class);
		customerService.edit(c);
		request.setAttribute("msg", "恭喜,编辑客户成功!");
		return "f:/msg.jsp";
	}
	
	public String query(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		/*
		 * 1. 封装表单数据到Customer对象中,它只有四个属性(cname、gender、cellphone、email)
		 *   它就是一个条件
		 * 2. 使用Customer调用service方法,得到List<Customer>
		 * 3. 保存到request域中
		 * 4. 转发到list.jsp
		 */
		Customer criteria = CommonUtils.toBean(request.getParameterMap(), Customer.class);
		List<Customer> cstmList = customerService.query(criteria);
		request.setAttribute("cstmList", cstmList);
		return "/list.jsp";
	}
}

dao层(持久层)

/**
 * 持久层
 * 
 * @author cxf
 * 
 */
public class CustomerDao {
	private QueryRunner qr = new TxQueryRunner();

	/**
	 * 添加客户
	 * 
	 * @param c
	 */
	public void add(Customer c) {
		try {
			String sql = "insert into t_customer values(?,?,?,?,?,?,?)";
			Object[] params = { c.getCid(), c.getCname(), c.getGender(),
					c.getBirthday(), c.getCellphone(), c.getEmail(),
					c.getDescription()};
			qr.update(sql, params);
		} catch(SQLException e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 查询所有
	 * @return
	 */
	public List<Customer> findAll() {
		try {
			String sql = "select * from t_customer";
			return qr.query(sql, new BeanListHandler<Customer>(Customer.class));
		} catch(SQLException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 加载客户
	 * @param cid
	 * @return
	 */
	public Customer load(String cid) {
		try {
			String sql = "select * from t_customer where cid=?";
			return qr.query(sql, new BeanHandler<Customer>(Customer.class), cid);
		} catch(SQLException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 编辑客户
	 * @param c
	 */
	public void edit(Customer c) {
		try {
			String sql = "update t_customer set cname=?,gender=?,birthday=?," +
					"cellphone=?,email=?,description=? where cid=?";
			Object[] params = {c.getCname(), c.getGender(),
					c.getBirthday(), c.getCellphone(), c.getEmail(),
					c.getDescription(), c.getCid()};
			qr.update(sql, params);
		} catch(SQLException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 多条件组合查询
	 * @param criteria
	 * @return
	 */
	public List<Customer> query(Customer criteria) {
		try {
			/*
			 * 1. 给出sql模板
			 * 2. 给出参数
			 * 3. 调用query方法,使用结果集处理器:BeanListHandler
			 */
			/*
			 * 一、 给出sql模板
			 * 二、 给出参数!
			 */
			/*
			 * 1. 给出一个sql语句前半部
			 */
			StringBuilder sql = new StringBuilder("select * from t_customer where 1=1");
			/*
			 * 2. 判断条件,完成向sql中追加where子句
			 */
			/*
			 * 3. 创建一个ArrayList,用来装载参数值
			 */
			List<Object> params = new ArrayList<Object>();
			String cname = criteria.getCname();
			if(cname != null && !cname.trim().isEmpty()) {
				sql.append(" and cname like ?");
				params.add("%" + cname + "%");
			}
			
			String gender = criteria.getGender();
			if(gender != null && !gender.trim().isEmpty()) {
				sql.append(" and gender=?");
				params.add(gender);
			}
			
			String cellphone = criteria.getCellphone();
			if(cellphone != null && !cellphone.trim().isEmpty()) {
				sql.append(" and cellphone like ?");
				params.add("%" + cellphone + "%");
			}
			
			String email = criteria.getEmail();
			if(email != null && !email.trim().isEmpty()) {
				sql.append(" and email like ?");
				params.add("%" + email + "%");
			}
			
			/*
			 * 三、执行query
			 */
			return qr.query(sql.toString(), 
					new BeanListHandler<Customer>(Customer.class), 
					params.toArray());
		} catch(SQLException e) {
			throw new RuntimeException(e);
		}
	}
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值