JavaWeb开发知识总结(内省,MVC,事务)

来源:互联网 发布:数据库宝典 编辑:程序博客网 时间:2024/06/03 04:10

JavaWeb开发知识总结(内省,MVC,事务)

1. 内省技术概述

1.1 JavaBean类

JavaBean类是符合特定要求的Java类.

​ JavaBean类需要符合以下要求:

  1. 提供无参的构造方法;
  2. 属性私有化;
  3. 属性提供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();        }    }}
原创粉丝点击