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);
		}
	}
}

分页

时间: 2024-10-11 02:23:14

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

【框架】[Hibernate]利用Hibernate进行单表的增删改查-Web实例

转载请注明出处:http://blog.csdn.net/qq_26525215 本文源自[大学之旅_谙忆的博客] 前面两篇博客已经将Hibernate的基础知识讲解得差不多了,差不多到写实例的时候了. 本篇只用hibernate进行单表的增删改查. 应用Hibernate,对students表进行增删改查. service层和DAO层,我都是直接写实现类了(因为这里主要是演示一下Hibernate的使用),如果是开发项目,注意一定要写接口! 准备数据库: 首先准备一个students表: cr

django 利用ORM对单表进行增删改查

牛小妹上周末,一直在尝试如何把数据库的数据弄到界面上.毕竟是新手,搞不出来,文档也看不懂.不过没关系,才刚上大学.今晚我们就来解释下,要把数据搞到界面的第一步.先把数据放到库里,然后再把数据从库里拿出来. 以下内容,参考django官方文档 . 1.创建MODEL 这里和官方文档一致.直接拷出来,放到一个叫models的py文件里面.若是你的项目中没有,一定不要觉得无处写代码.你自己建一个即可 同步数据库: 执行以下命令.不懂的可以参考:django连接mysql python manage.p

SpringBoot JPA实现增删改查、分页、排序、事务操作等功能

今天给大家介绍一下SpringBoot中JPA的一些常用操作,例如:增删改查.分页.排序.事务操作等功能.下面先来介绍一下JPA中一些常用的查询操作: //And --- 等价于 SQL 中的 and 关键字,比如 findByHeightAndSex(int height,char sex): public List<User> findByHeightAndSex(int height,char sex); // Or --- 等价于 SQL 中的 or 关键字,比如 findByHeig

JavaWeb程序利用Servlet的对SQLserver增删改查操作

声明:学了几天终于将增删改查的操作掌握了,也发现了一些问题,所以总结一下. 重点:操作数据库主要用的是SQL语句跟其他无关. 一:前提知识:PreparedStatement PreperedStatement是Statement的子类,它的实例对象可以通过调用Connection.preparedStatement()方法获得,相对于Statement对象而言:PreperedStatement可以避免SQL注入的问题. Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出.P

利用SpringBoot实现RestFul风格的增删改查操作

会遇到的问题:1.在提交delete请求时,可能会报405错误,解决办法在配置文件中加入在配置文件中加入spring.mvc.hiddenmethod.filter.enabled=true启用隐藏方法过滤器 2.可能会遇到Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource ,解决办法:自己检查controller的请求头是不是有重复的 说明:这个小项目没有使用数据

创建支持CRUD(增删改查)操作的Web API

一:准备工作 你可以直接下载源码查看 Download the completed project.     下载完整的项目 CRUD是指“创建(C).读取(R).更新(U)和删除(D)”,它们是四个基本的数据库操作.许多HTTP服务也会通过REST或类REST的API模拟CRUD操作. 在本教程中,我们将建立一个十分简单的Web API来管理一列产品. 每个产品包含一个name(名称).price(价格)和category(分类)(如,“toys(玩具)”.“hardware(硬件)”等),还

关于利用PHP访问MySql数据库的逻辑操作以及增删改查实例操作

PHP访问MySql数据库 <?php //造连接对象$db = new MySQLi("localhost","root","","0710_test"); //写SQL语句$sql = "select * from student";//检测连接数据库是否成功,失败返回"连接失败",并退出程序 if(mysqli_connect_error()){    die("连

利用SQLiteOpenHelper创建数据库,进行增删改查操作

Android中提供SQLiteOpenHelper类,在该类的构造器中,调用Context中的方法创建并打开一个指定名称的数据库对象.继承和扩展SQLiteOpenHelper类主要做的工作就是重写以下两个方法.onCreate(SQLiteDatabase db) : 当数据库被首次创建时执行该方法,一般将创建表等初始化操作在该方法中执行. onUpgrade(SQLiteDatabse dv, int oldVersion,int new Version):当打开数据库时传入的版本号与当前

权限管理系统之LayUI实现页面增删改查和弹出层交互

由于对LayUI框架不太熟悉,昨天抽空看了下LayUI的文档,今天在网上找了使用LayUI进行增删改查相关内容,自己照葫芦画了个瓢,画瓢部分不是很难,主要是下午遇到了一个弹出层的问题耗时比较久. 同一项目,设计风格都差不多,对于涉及单个数据表的页面,基本都是增删改查,布局都是差不多,实际项目中都是复制.粘贴过来改下数据基本就能完成80%,后续就是修修补补或者是要实现一些特殊需求,记得刚参加工作时,老大直接给了一个已经做好的模板页面让我比对着手动敲一遍,当时觉得重复操作没啥用,现在再看觉得作用很大