JavaWeb开发知识总结(内省,MVC,事务)
来源:互联网 发布:数据库宝典 编辑:程序博客网 时间:2024/06/03 04:10
JavaWeb开发知识总结(内省,MVC,事务)
1. 内省技术概述
1.1 JavaBean类
JavaBean类是符合特定要求的Java类.
JavaBean类需要符合以下要求:
- 提供无参的构造方法;
- 属性私有化;
- 属性提供public修饰的get和set方法.
1.2 内省技术
内省就是用来获取JavaBean类的属性或属性的get/set方法.
注意事项: :javabean中的属性是通过get或set方法确定的,只要有这两个方法就是javabean的属性,而不只包含自定义属性.
内省机制的原理:
通过内省机制获取javabean对象的属性,通过属性的名字和被封装数据map集合中key相同时,通过反射调用属性的set方法将map集合中对应的值存储到javabean对象对应的属性中.使用的案例代码如下:
/** * 封装BeanUtils方法 * Map集合key是String,value是String[]类型 * @param object javabean对象 * @param map 要封装的数据 */public static void _populate(Object object, Map<String, String[]> map) { // 获取javabean类的描述类 BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass()); // 获得描写javabean的属性描述的PropertyDescriptor数组 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); // 遍历属性的数组 for (PropertyDescriptor pd : pds) { // 当map集合中存储的key和javabean中属性名相同时 // 调用javabean中属性对应的set方法进行赋值 if(map.containsKey(pd.getName())) { // 通过反射获取javabean类的set方法 Method method = pd.getWriteMethod(); // 获取Map集合对应value中数组的第一个数据 Object obj = map.get(pd.getName())[0]; // 执行该属性的set方法 method.invoke(object, obj); } }}
注意事项: 内省机制在将标签中数据封装到javabean对象对应的属性中时是通过名称进行匹配的,因此要求jsp页面中提交数据中的参数名需要和javabean对象中属性名称对应一致.
2. MVC设计模式
MVC设计模式是指JavaWeb开发的一种设计思想,其实指的是V(JSP)+C(Servlet)+M(JavaBean)
开发模式 ,M(Model)代表模型,V(View)代表视图,C(Controller)代表控制器.JavaEE开发分为三层结构:web层
,业务层
,持久层
,其中web层包含Servlet层和jsp层;MVC中的M对应是业务层和持久层,V对应的Web层的jsp层,C对应的web层中Servlet层.
3. 数据库事务
事务是指事务指的是逻辑上的一组操作,组成这组操作的各个逻辑单元要么一起成功,要么一起失败(同生共死).
3.1 MYSQL数据库中事务管理
MYSQL中开启事务:
-- 方式1.手动开启事务start transaction; -- 开启事务-- 多条sql语句;commit/rollback; -- 提交或回滚事务-- 方式2.设置一个自动提交参数show variables like '%commit%'; -- 查看与commit相关参数.set autocommit = 0; -- 将autocommit参数设置为OFF,不自动提交,当写完SQL语句需要手动提交事务. 0或者off均可
3.2 事务特性(ACID):
# 原子性: 强调事务中操作不能分割开# 一致性: 强调事务执行前后,数据的完整性要一致# 隔离性: 事务之间的执行不相互影响# 持久性: 事务执行提交或回滚后,数据有持久的保存在了数据库中
3.2 不考虑事务隔离性引发的问题:
# 一类读问题: * 脏读: 一个事务读取到另一个事务还没提交的数据 * 不可重复读: 一个事务读取到了另一个事务中update更新的数据,导致该事务中多次读取的数据不一致 * 幻读/虚读: 一个事务读取到了另一个事务中insert插入的数据,导致在当前事务中多次查询的结果不一致# 一类写问题: * 引发两类丢失更新
3.3 事务隔离级别解决隔离性引发的问题:
MYSQL数据库默认的隔离级别是repeatable read; Oracle数据库隔离级别是read committed.
# read uncommitted:未提交读.脏读,不可重复读,虚读都可能发生. 性能高;# read committed:已提交读.避免脏读.但是不可重复读和虚读有可能发生;# repeatable read:可重复读.避免脏读,不可重复读.但是虚读有可能发生;# serializable:串行化的.避免脏读,不可重复读,虚读的发生. 性能低,一个事务结束后其他事务才能执行.
事务隔离级别相关的常用命令:
select @@tx_isolation; -- 查看当前的事务的隔离级别set session transaction isolation level 事务的隔离级别; -- 设置事务的隔离级别如: set session transaction isolation level read uncommitted; -- 设置事务隔离级别是未提交读
注意事项: 设置事务的隔离级别是针对本事务而言的,就是说设置的本事务中是否能脏读/不可重复读/幻读到其他事务操作中的数据;而不是设置本事务不能出现这些隔离性引发的问题.
4. 使用程序进行事务的管理(重点)
在JavaWeb的MVC模式下,需要在业务层(service层)进行事务的管理,事务的管理是通过Connection对象中的方法实现的,事务管理是思想是:在业务层业务执行前开启事务,执行SQL语句,提交事务,当SQL语句执行过程中出现异常时,使用Connection对象回滚事务.
在业务层有三种事务管理的方式:使用的事务相关的API使用详见JDBC相关知识,以转账案例说明
方式一:在业务层获得Connection数据库连接对象,将Connection对象传递给dao层,并在业务层进行事务的管理
/** * User的DAO * 通过业务层传递的Connection对象进行操作 */public class UserDao { /** * 扣钱方法 * @param username 账户 * @param money 金额 * @throws SQLException */ public void subtractMoney(Connection conn, String username, Double money) throws SQLException { QueryRunner queryRunner = new QueryRunner(); queryRunner.update(conn, "update account set money=money - ? where username=?", money, username); } /** * 加钱的方法 * @param username 账户 * @param money 金额 * @throws SQLException */ public void addMoney(Connection conn, String username, Double money) throws SQLException { QueryRunner queryRunner = new QueryRunner(); queryRunner.update(conn, "update account set money=money + ? where username=?", money, username); }}
/** * 转账业务的service */public class UserService { /** * 转账业务方法 * @param fromuser 源账户 * @param touser 目的账户 * @param money 金额 */ public void transfer(String fromuser, String touser, Double money) { UserDao userDao = new UserDao(); Connection conn = JDBCUtils.getConnection(); try{ // 设置事务不自动提交 conn.setAutoCommit(false); userDao.addMoney(conn, touser, money); // int i = 1/0; 出现异常时后续代码不执行 userDao.subtractMoney(conn, fromuser, money); // 提交事务 conn.commit(); } catch(Exception e) { try { // 回滚事务 conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); } finally { if(conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } conn = null; } } }}
/** * 数据库操作的工具类 */public class JDBCUtils { // 定义c3p0的数据库连接池 private static final ComboPooledDataSource cpds = new ComboPooledDataSource(); /** * 获取数据库的连接 * @return 返回数据库连接对象 */ public static Connection getConnection() { Connection conn = null; try { conn = cpds.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return conn; } /** * 获取数据库连接池 * @return 返回数据库连接池对象 */ public static DataSource getDataSource() { return cpds; }}
方式二:通过DbUtils工具类管理事务,但本质和方式1相同,也需要在业务层创建Connection对象
/** * 转账业务的service * UserDao类和JDBCUtils类和方式一对应的类相同 */public class UserService3 { public void transfer(String fromuser, String touser, Double money) { UserDao userDao = new UserDao(); Connection conn = JDBCUtils.getConnection(); try{ // 设置事务不自动提交 conn.setAutoCommit(false); userDao.addMoney(conn, touser, money); int i = 1/0; // 出现异常时后续代码不执行 userDao.subtractMoney(conn, fromuser, money); // 提交事务 DbUtils.commitAndCloseQuietly(conn); } catch(Exception e) { // 回滚事务 DbUtils.rollbackAndCloseQuietly(conn); e.printStackTrace(); } }}
方式三(重点): 在业务层进行事务的管理但是不创建或获取Connection对象,降低业务层和dao的耦合性.
思路:由于tomcat在接收到客户端的请求后会创建一个线程去执行Servlet中的service方法,由于每次请求后都是一个线程在执行,则可以将Connection对象存储到本地线程ThreadLocal
中.
/** * User的DAO * 通过工具类中设置连接对象进行数据库的 */public class UserDao2 { /** * 扣钱方法 * @param username 账户 * @param money 金额 * @throws SQLException */ public void subtractMoney(String username, Double money) throws SQLException { QueryRunner queryRunner = new QueryRunner(); queryRunner.update(JDBCUtils2.getConnection(), "update account set money=money - ? where username=?", money, username); } /** * 加钱的方法 * @param username 账户 * @param money 金额 * @throws SQLException */ public void addMoney(String username, Double money) throws SQLException { QueryRunner queryRunner = new QueryRunner(); queryRunner.update(JDBCUtils2.getConnection(), "update account set money=money + ? where username=?", money, username); }}
/** * 数据库操作的工具类 * 通过ThreadLocal类存储当前请求的Connection对象 */public class JDBCUtils2 { // 定义c3p0的数据库连接池 private static final ComboPooledDataSource cpds = new ComboPooledDataSource(); // 定义本地线程对象,本质是map集合,其中key是和每次线程相关,value是Connection对象 // 则每次请求创建的线程都会创建自己的Connection对象并存储到本次线程中 // 则业务层直接调用该工具类中的方法,该方法中的Connection对象是对应线程的Connection对象 private static final ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); /** * 获取数据库的连接 * @return 返回数据库连接对象 */ public static Connection getConnection() { Connection conn = tl.get(); if(conn == null) { try { conn = cpds.getConnection(); tl.set(conn); } catch (SQLException e) { e.printStackTrace(); } } return conn; } /** * 设置事务是否是自动提交 * @param flag 当为true时自动提交事务,false不自动提交事务 */ public static void setAutoCommit(boolean flag) { try { JDBCUtils2.getConnection().setAutoCommit(flag); } catch (SQLException e) { e.printStackTrace(); } } /** * 提交事务 */ public static void commit() { try { JDBCUtils2.getConnection().commit(); } catch (SQLException e) { e.printStackTrace(); } } /** * 回滚事务 */ public static void rollback() { try { JDBCUtils2.getConnection().rollback(); } catch (SQLException e) { e.printStackTrace(); } } }
/** * 转账业务的service */public class UserService2 { public void transfer(String fromuser, String touser, Double money) { UserDao2 userDao = new UserDao2(); try{ // 设置事务不自动提交 JDBCUtils2.setAutoCommit(false); userDao.addMoney( touser, money); int i = 1/0; // 出现异常时后续代码不执行 userDao.subtractMoney( fromuser, money); // 提交事务 JDBCUtils2.commit(); } catch(Exception e) { // 回滚事务 JDBCUtils2.rollback(); e.printStackTrace(); } }}
- JavaWeb开发知识总结(内省,MVC,事务)
- JavaWeb开发知识总结(tomcat)
- JavaWeb开发知识总结(tomcat)
- JavaWeb开发知识总结(Listener)
- JavaWeb开发知识总结(filter)
- JavaWeb开发知识总结(网上商城项目总结)
- JavaWeb前端开发知识总结(HTML)
- JavaWeb前端开发知识总结(CSS)
- JavaWeb前端开发知识总结(javaScript)
- JavaWeb前端开发知识总结(jQuery)
- JavaWeb前端开发知识总结(mysql)
- JavaWeb数据库开发知识总结(jdbc基础)
- JavaWeb数据库开发知识总结(jdbc进阶)
- JavaWeb数据库开发知识总结(xml)
- JavaWeb前端开发知识总结(CSS)
- JavaWeb开发知识总结(HTTP,servlet)
- JavaWeb开发知识总结(HttpServletRequest,HttpServletResponse)
- JavaWeb开发知识总结(HTTP,servlet)
- SQL解析利器General SQL Parser
- JQ实现手风琴菜单
- 线性表的链式存储
- 历史上mysql最经典的34个SQL语句(百看不厌)
- 汇编2——完整的例子集合
- JavaWeb开发知识总结(内省,MVC,事务)
- 【工具】C盘垃圾自动清理软件
- Oracle Histogram 基础介绍
- 数学:非线性方程的求解---(笔记+代码)
- js原生学习-初级-练习03
- JavaScript中的闭包
- jdk源码解析--set
- TensorFlow23: “恶作剧” --人脸检测
- malloc,realloc,calloc和new分配内存