Web阶段(day15,log4j&事务)

1.log4j
    1.1 1og4j概述
    log for java 在Java语言中最常使用的日志收集框架,基本在企业中已经占据主导地位。
    1.2 使用log4j
    导入开发包,因为javaee不包含java4j,需要手动导入。
    在src目录下引入名称为log4j.properties文件。
    info 总体日志级别, stdout管道1, D管道2,E管道 (日志文件中可以不写管道,但是不能不数据池,就是下面的一些配置信息。)
    log4j的日志结构
        在log4j使用时,log4j.properties文件总共非三部分组成,分别为收集日志的优先级,收集日志的输出目的地,收集日志的输出格式。
        日志的优先级:使用log4j时可以指定日志输出的级别,指定级别之后,在当前其以上级别的日志都会输出。(日志的级别可以由用户任意指定。)
        off 最高等级,用于关闭所有日志记录。
        fatal 指出每个严重的错误事件将会导致应用程序的推出。
        error 指出虽然发生错误事件,但仍然不影响系统的继续运行。
        warn 表明会出现潜在的错误情形。
        info 一般和在粗粒度级别上,强调应用程序的运行全过程。
        debug 一般用于细粒度级别上,对调试应用程序非常有帮助。
        all 最低等级,用于打开所有日志记录。
        日志的输出目的地:日志输出的位置。(console,文件)
        org. apache. log4j. ConsoleAppender(控制台) ,
        org. apache. log4j. FileAppender(文件) ,
        org. apache. log4j. DailyRollingFileAppender(每天产生一个日 志文件) ,
        org. apache. log4j. RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件) ,
        org. apache. log4j. WriterAppender(将日 志信息以流格式发送到任意指定的地方)
        日志输出格式layout
        org. apache. log4j. HTMLLayout(以HTML表格形式布局) ,
        org. apache. log4j. PatternLayout(可以灵活地指定布局模式) ,
        org. apache. log4j. SimpleLayout(包含日 志信息的级别和信息字符串) ,
        org. apache. log4j. TTCCLayout(包含日 志产生的时间、 线程、 类别等等信息)
        日志输出格式的正则:
        %p 输出优先级, 即DEBUG, INFO, WARN, ERROR, FATAL
        %r 输出自 应用启动到输出该log信息耗费的毫秒数
        %c 输出所属的类目 , 通常就是所在类的全名
        %t 输出产生该日 志事件的线程名
        %n 输出一个回车换行符, Windows平台为“rn”, Unix平台为“n”
        %d 输出日 志时间点的日 期或时间, 默认格式为ISO8601, 也可以在其后指定格式, 比如: %d{yyy MMM dd HH: mm: ss, SSS}, 输出类似: 2002年10月 18日 22: 10: 28, 921
        %l 输出日志事件的发生位置, 包括类目 名、 发生的线程, 以及在代码中的行数。 举例: Testlog4. main(TestLog4. java: 10)
        %m  代表日志信息
    1.3 log4j实现
        通过Logger类创建一个logger对象
        public static Logger logger = Logger.getLogger(Class);
        //参数位置存储类的字节码,表示哪个类产生的错误。
        import org.apache.log4j.Logger;
        //log4j日志框架测试
        public class Demo1 {
            //创建一个logger对象
            public static Logger  logger = Logger.getLogger(Demo1.class);
            public static void main(String[] args) {
                logger.fatal("这是一个致命错误");
                logger.error("这是一个严重错误");
                logger.warn("这是一个警告信息");
                logger.info("这是一个普通信息");
                logger.debug("这是一个调试信息");
            }
        }
2.事务
    2.1 事务概述
        在一个事件中可能有多个步骤,这些步骤要么全部成功,要么全部失败,这个事件就称之为一个事务。
        开启一个事务:start transaction
        提交事务:commit
        回滚事务:rollback
    2.2 JDBC操作事务
        conn.setAutoCommit(boolean); 如果设置为true则一个sql就是一个事务,单条sql语句会在数据库中直接提交执行,如果设置为false,则接下来的所有sql都会作为事务中的sql语句,等待commit或rollback操作。
        conn.commit() 提交事务,数据库中的数据发生真实的变化。
        conn.rollback() 回滚事务,之前书写sql认为全部失败,数据库中的数据不会发生变化。
        conn.Savepoint() 设置保存点,在回滚事务时,可以选择回滚值保存点所在的位置。保存点之前的代码依然可以进行提交操作。
        案例:事务实现提交、保存点、回滚。
            import java.sql.Connection;
            import java.sql.PreparedStatement;
            import java.sql.SQLException;
            import com.mchange.v2.c3p0.ComboPooledDataSource;
            import com.mchange.v2.c3p0.ComboPooledDataSource;
            //保存点实现
            public class TransDemo2 {
                public static void main(String[] args) {
                    Savepoint sp = null;
                    Connection conn = null;
                    PreparedStatement ps = null;
                    ComboPooledDataSource source = new ComboPooledDataSource();
                    try {
                        conn = source.getConnection();
                        conn.setAutoCommit(false);//启动事务
                        //小a减一百
                        ps = conn.prepareStatement("update user set money = money -100 where name = ?");
                        ps.setString(1, "a");
                        ps.executeUpdate();
                        //小b加一百
                        ps = conn.prepareStatement("update user set money = money +100 where name = ?");
                        ps.setString(1, "b");
                        ps.executeUpdate();
                        //保存点   
                        sp = conn.setSavepoint();
                        //小a减一百
                        ps = conn.prepareStatement("update user set money = money -100 where name = ?");
                        ps.setString(1, "a");
                        ps.executeUpdate();
                        int i=1/0;
                        //小b加一百
                        ps = conn.prepareStatement("update user set money = money +100 where name = ?");
                        ps.setString(1, "b");
                        ps.executeUpdate();
                        //要么提交事务,要么回滚事务
                        conn.commit();
                    } catch (Exception e) {
                        e.printStackTrace();
                        if(conn != null){
                            try {
                                if(sp != null){//sp初始值为null,保证不为null才能回滚使用。
                                    //回滚到保存点sp
                                    conn.rollback(sp);
                                    //保存点之前存在的sql,正常提交
                                    conn.commit();
                                }
                            } catch (SQLException e1) {
                                    e1.printStackTrace();
                            }
                        }
                    }finally{
                        if(ps != null){
                            try {
                                ps.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }finally{
                                ps = null;
                            }
                        }
                        if(conn != null){
                            try {
                                conn.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }finally{
                                conn = null;
                            }
                        }
                    }
                }
            }

    2.3 事务四大特性:ACID
        原子性(Atomicity):组成事务的单位,涉及多个操作,这些操作要么全部成功要么全部失败,这个特性就是事务的原子性。
        一致性(Consistency):事务发生前后,数据在完整性上任然保持一致。
        隔离性(Isolation):线程安全问题。在一个用户使用事务访问数据时,另外一个事务可能对当前事务产生影响,如果要规避这种影响,则需要对两个事务进行线程处理,这个处理过程就是设置数据库隔离性。
        持久性(Durability):一旦事务提交,数据库中数据就会发生真实的修改,这个过程是不可逆的,没有任何操作可以撤销这个修改。
    2.4 隔离性
        隔离性的本质:希望解决在数据库中出现的和事务有关的线程安全问题。
        两个线程同时查询一张表:
            不会出现线程安全问题。
        两个线程同时更新一张表:
            一定会出现线程安全问题。添加锁机制。
        一个线程读,一个线程写:
            面对一个线程度,一个线程写,需要根据具体情况来表明是否关心出现的线程安全问题。数据库为了解决这个问题,提出了隔离性,但是并未对隔离性作出实现。而是为用户提供了四个选项,用户可以根据自己的需求,通过这四个选项,修改数据库的隔离级别,而达到线程安全的不同要求。
        总结:如果需要解决脏读问题,则修改数据库的隔离级别为read committed 及其以上级别。
        如果需要解决脏读、不可重复读,则修改数据库的 隔离级别为repeatable read 及其以上级别。
        如果需要解决脏读、不可重复读,虚度(幻读)则修改隔离级别为serializable。
        serializable是一个串行化的模式。对于数据
        脏读:一个事务读取到另一个事务未提交的数据,这个情况称之为脏读。
        不可重复读:一个事务读取到了另一个已经提交的事务的数据,导致事务提交前后读取到的内容不一致,这种现象称之为不可重复度。
        虚读(幻读):一个事务读取到另外一个事务已经提交的数据,最后做出了整表操作,这种请况称之为虚读(幻读)。一般不会出现。

        数据库隔离级别,就是为了消除在多个事务之间产生的线程安全问题所存在的一个数据库安全形式。
        数据库隔离级别:
            read uncommitted 数据库隔离级别最低。可能会出现脏读,不可重复读,虚读(幻读)。数据库的性能最高。
            read committed  数据库隔离级别较低,可以防止脏读,可能会出现不可重复度,虚度(幻读)。数据库的性能较高。
            repeatable read 数据库隔离级别较高,可以防止脏读,不可重复读。可能会出现虚度(幻读)。数据库的性能较弱。数据库默认的隔离级别。
            serializable 数据库隔离级别最高。可以防止脏读,不可重复度和虚读/幻读。数据库的性能最弱,称之为串行化模式。
            修改数据库隔离级别:
        set global/session transation isolation level read uncommitter;//全部或会话。    
        set transation isolation level read uncommitter;// 对下一次事务进行隔离级别修改。
        查看当前窗口隔离级别:
            select @@tx_isolation;
        隔离级别之下的数据库性能和安全
            性能:read uncommitted>read committed>repeatable> serializable
            安全:serializable>repeatable>read commotted>read uncommitted
            在真实的开发情景中,read uncommitted可能出现的问题太多,不会使用。serializable性能太差,也不会使用,一般会采用read committed或者 repeatable read二者之一。而且数据库mysql默认隔离级别就是repeatable read。
        serializable隔离级别之下的情景分析——锁机制。
            在非serializable隔离级别中查询不添加锁。在serializable隔离级别之下查询会添加共享锁。增删改都会添加排他锁。
            共享锁和共享锁可以共存。
            共享锁和排它锁不能共存。
            排它锁和排它锁不能共存
        表级锁和行级锁
        表级锁:可以将操作的表完整锁住,任何操作本张表的事务,都需要等待上一次的事务完成。
        行级锁:可以将操作的行完整做主,任何操作当前行的事务,都需要等待
        死锁:两个线程相互等待对方释放资源,这个等待的过程就称之为死锁。
        解决死锁:
            i.销毁一个线程,使得另外一个线程可以得到资源,继续运行。
            ii.修改代码,防止现象产生。
        乐观锁和悲观锁(乐观取第一个,悲观取最后一个。)

你可能感兴趣的:(Web阶段学习笔记)