java面试题目(下)部分2016


=======================================Hibernate================================= 介绍一下Hibernate Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对 象编程思维来操纵数据库 Hibernate的核心接口一共有5个: 分别为:Session、SessionFactory、Transaction、Query和Configuration。 1:Session接口:Session接口负责与数据库打交道。 2:SessionFactory接口:SessionFactroy接口负责初始化Hibernate。创建Session对象。 (这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就 够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。) 3:Configuration接口:Configuration接口负责读取配置文件获取连接数据的信息并且启动Hibernate,创建SessionFactory对象。 4:Transaction接口:Transaction接口负责处理事务。 5:Query和Criteria接口:Query和Criteria接口负责执行各种数据库查询。它可以使用HQL语言或SQL语句两种表达方式。 为什么使用hibernate 1: 对jdbc的封装。简化了dao层编码工作,使用简单。 2:Hibernate 性能好,有缓存机制和数据抓取机制提高性能。 3:Hibernate 使用 java 的反射机制,而不是字节码增强程序类实现透明性 4:Hibernate 的性能非常好,映射的灵活性很出色。它支持很多关系型数据库。 5:Hibernate 最大的特点就是没有侵入性,也就是说 javaBean 不需要继承任何超类. 移植性好。 请你谈谈 JDBC 与 Hibernate 的关系? 答:Hibernate 是对 JDBC 的轻量级的封装,它是一个独立的对象持久层框架, Hibernate 可以用在任何 JDBC 可以使用的场合。 什么是 Hibernate 延迟加载 所谓延迟加载就是当在真正需要数据的时候,才发 sql 操作数据库。 如:hibernate 的 load 方法就是采用延迟加载机制。 什么是 Hibernate 抓取策略: 在主从表的结构中:查询主表的数据是否立即把从表的数据也查询出来。 @OneToMany(mappedBy="deparemt",fetch=FetchType.LAZY,cascade={CascadeType.ALL}) 如果在主对象一方设置:fetch=FetchType.LAZY: 则查询主表数据不会立即查询从表的数据:也就是延迟加载。 主对象默认方式就是:fetch=FetchType.LAZY: sessionFactory:负责创建 session Session: 负责对数据库的操作 Configuration:读取配 置文件:启动 hibernate 创建 session 工厂 Query 接口查询 Criteria 查询 Transaction 事务处理 原生 SQL 查询 save() update() delete() load() get() 如果在主对象一方设置:fetch=FetchType.EAGER: 则查询主表数据时也会查询从表的数据:也就是立即加载,采用的外连接的方式。 @OneToMany(mappedBy="deparemt",fetch=FetchType.EAGER,cascade={CascadeType.ALL}) 什么是 Hibernate 的级联: 如果在主对象一方设置了:cascade={CascadeType.ALL} 增加时。保存主对象,从对象会一起自动保存 删除时,删除主对象,从对象一起删除。 修改时,修改主对象,从对象一起修改保存。 Hibernate 的工作原理. hibernate,通过对 jdbc 进行封装,对 java 类和关系数据库进行映射,实现了对关系数据库的面向对象方式的操作, 改变了传统的 jdbc + sql 操作数据的方式,从而使开发人员可以话更多精力进行对象方面的开发 流程:如下: 1:读取 hibernate 的配置文件创建 SessionFactory 2:获取 session 3:开始事务 4:持久化操作 5:提交事务 6:关闭 Session 1:Hibernate 的 get 和 load 方法的区别 当查询的数据不存在时表现不一样:load:延迟检索 get:立即检索 1:load 返回的是代理对象,等到要用该对象时,才会发 sql 语句从数据库取, 当数据库没有对应的记录时会报错 2:get 直接从数据库加载,不会延迟加载,当数据库没有对应的记录时返回 null. =====================================hibernate 的缓存============================== 缓存只对查询有效 更新 删除不涉及缓存优化 而是再更新或删除数据库中的对象的同时 更新后修改缓存中对象 缓存只能建立在同一种查询机制上 例如:HQL--criteria 和 session.createQuery 是不能共用同一个缓存的 说下 Hibernate 的缓存机制 1:hibernate 一级缓存: 是 session 级别的缓存,只能缓存对象。 2:二级缓存: 独立于 session,是 sessionFactory 级别的缓存,只能缓存对象 3:用户查询缓存:是针对普通属性结果集的缓存,对实体对象的结果集只缓存 id 对于经常使用的查询,如果启用了缓存 当第一次执行查询时,hibernate 会把查询结果存放缓存中。 以后再执行该查询时,只需从缓存中获得查询结果,从而提高性能。 查询缓存:只会缓存属性不会缓 存对象。用查询缓存既可以查属 性也可以查对象。 查属性时,该属性存于该缓存中, 下次再查该属性时。直接从缓存 中拿不会去查数据库。 查对象时只缓存对象的主键 ID 下次查该对象时,根据主键 ID 的 值从二级缓存中去找,找到命中, 没找到去数据库查。所以查询缓 存依赖于二级缓存。 二级缓存给一级缓存 get /load 方法提供数据 Session1 Session2 一级缓存 二级缓存: 只缓存对象。不缓存属性 list()方法:只会刷新二级缓存。也就是每次调用 list() 方法都会查询数据库。 Iterator():方法:会利用二级缓存。但是有 N+1 问题 (查询 10 条数据会发 11 条 sql 语句,一条查对象主键 另外 10 条查具体的数据对象) 数据库 查询缓存对 list 方法有效 对 iterator()方法无效。和二级缓存相 反 一级缓存二级缓存查询缓存都在内存 中 Hibernate 的一级缓存和二级缓存的区别? 一级缓存是 session 级别的缓存,不能删除只能管理。二级缓存可以配置,给一级缓存提供数据。 list 与 iterator 区别 1:List 仅仅会填充二级缓存,却不能利用二级缓存:当打开查询缓存时:list 能利用查询缓存。 List 是一次读出所有的数据: 2:iterator 可以读二级缓存,先从缓存中取数据:没有数据时 iterator 首先读出所有的 id.等用到时才会根据 id 发送 sql 语句从 数据库读数据,有 N+1 问题:查询 n 条数据要发送 n+1 条 sql 语句。 ------------------------------------------------------------------------------------------------------------------------------------------ 2.在Hibernate中进行多表查询,每个表中各取几个字段,也就是说查询出来结果集并没有个实体类来对应,如何解决这个问题? 解决方案:用 HQL 多属性查询,查询出数据是对象数组,我们自己重新组装成对象 vo。 Hibernate 的三种状态的转换:持久状态 -------临时状态 ------托管状态 Hibernate 的常用的主键类型: 1: native: 跨数据库时使用,由底层方言产生。:这个要先建一个公共的序列:hibernate_sequence 也可以自动生成。 对于 mysql sqlserver 主键为 int short long 设置主键为自增长就可以了。 对于 oracle 数据库:主键类型可以是 int long short varchar2. 2: sequence: 用于 oracle 数据库的自定义序列。 3: assigned: 自己定义主键的方式. 即不用序列(oracle)也不用自增长(mysql/sqlserver)=主键由程序来设定. 4: identity: mysql/sqlserver 的主键处理:主键字段是数字类型并且这时表的主键字段要设置为自增长 5: uuid.hex: 32 位 16 进制数字的字符串. 主键的类型是 varchar hibernate 的查询方式有几种? 1:session 的 get load 主键查询 分页查询。 2:HQL 查询 3:Query 查询 4:Criteria 查询 5:本地 SQL 查询 特点: HQL 功能最强大,适合各种情况,但是动态条件查询构造起来很不方便 Criteria 最适合动态条件查询,不太适合统计查询. NativeSQL 可以实现特定数据库的 SQL,但是不能跨数据库用 临时状态对象(Transient Objects): 数据库中没有此对象,只是存在内存中 瞬时对象在内存孤立存在,它是携带信息的载体,不和数据库的数据有任何关联关系,在 Hibernate 中,可通过 session 的 save() 或 saveOrUpdate()方法将瞬时对象与数据库相关联,并将数据对应的插入数据库中,此时该瞬时对象转变成持久化对象。 持久对象(Persist Objects):数据库中存在这个对象,已经纳入 Session 管理 处于该状态的对象在数据库中具有对应的记录,并拥有一个持久化标识(id)。如果是用 hibernate 的 delete()方法, 对应的持久对象就变成瞬时对象,因数据库中的对应数据已被删除,该对象不再与数据库的记录关联。 当一个 session 执行 close()或 clear()、evict()之后,持久对象变成脱管对象,此时持久对象会变成脱管对象,此时该对象虽然 具有数据库识别值,但它已不在 HIbernate 持久层的管理之下。 持久对象具有如下特点: 1. 和 session 实例关联; 2. 在数据库中有与之关联的记录。 脱管对象、游离状态(Detached Objects):数据库中还存在这个对象,只是没有纳入 Session 管理。 当与某持久对象关联的 session 被关闭后,该持久对象转变为脱管对象。当脱管对象被重新关联到 session 上时, 并再次转变成持久对象。 脱管对象拥有数据库的识别值,可通过 update()、saveOrUpdate()等方法,转变成持久对象。 脱管对象具有如下特点: 就是脱离了 session 的管理。 1. 本质上与零时对象相同,在没有任何变量引用它时,JVM 会在适当的时候将它回收; 2. 数据库有该对象对应的一条记录。 Hibernate 批量数据处理? 1:对于批量修改和批量删除用 HQL(对象 sql)。 2:对于批量增加:建议绕开 hibernate 的 api 直接用 jdbc 的批量处理:addBath() executeBath() clearBath() 3 : 如果数据量不大的情况下。也可以使用 hibernate 的 api 但是此时设置一个计数器,每执行一批数据后, 调用 session.flush(); session.clear(); 清除 session 中的数据防止内存溢出。一批一批的往数据库插入或者删除 修改。 hibernate 中 session 的线程安全问题 这里的 Session 并非指 HttpSession,可以理解为基于 JDBC 的 Connnection,Session 是 Hibernate 运作的中心, SessionFactory 负责创建 Session,SessionFactory 是线程安全的,多个并发线程可以同时访问一个 SessionFactory 并从中获取 Session 实例。 而 Session 并非线程安全,也就是说,如果多个线程同时使用一个 Session 实例进行数据存取, 则将会导致 Session 数据存取逻辑混乱.因此创建的 Session 实例必须在本地存取空上运行, ThreadLocal 是 Java 中一种较为特殊的线程绑定机制,通过 ThreadLocal 存取的数据, 总是与当前线程相关的。 ThreadLocal 并不是线程。是一种同步的 map 结构来实现的。 在 ThreadLocal 类中定义了一个 ThreadLocalMap, Map 中元素的键为当前线程对象,而值为:session。 可以这样来理解: 每一个线程获取的 session 都保存到:一个 map 中: private Map valueMap = Collections.synchronizedMap(new HashMap()); 同步 hashmap。 valueMap.put(Thread.currentThread(), 获取的 session); ①键为线程对象,值为本线程的变量副本也就是绑定的 session. 只要你在程序中不关闭当前的 session,再次操作数据库时拿出的 session 是同一个 session. 所以数据库的几个用户操作,各是各的 session 不相干的。 Hibernate 的事务隔离级别: 1:read – uncommitted:读操作未提交(读了未提交的数据)效率最高:但是会出现不可重复读、泛读、脏读。 2:read - committed:读操作已提交(读了已经提交的数据)hibernate 设置为这种:不会出现脏读,但是会出现不可重复读、泛读 幻读的重点在于新增或者删除。 4:repeatable read:可重复读:可能出现泛读 8:serializable:(可串行化锁表)解决一切问题。性能最低。Serializable 的级别最高 大多数数据库的默认隔离级别为: Read Commited,如 Sql Server , Oracle. 设定 hibernate 的事务隔离级别 hibernate.connection.isolation = 2 Hibernate 容器 数据库操 作 1 用户 数据库操 作 2 用户 数据库操 作 3 用户 Session1 Session2 2 当前线程 1 当前线程 3 当前线程 2 Session3 ==========================Hibernate 笔试题==================================== (1)一般情况下,关系数据模型与对象模型之间有哪些匹配关系(多选) A)表对应类 B)记录对应对象 C)表的字段对应类的属性 D)表之间的参考关系对应类之间的依赖关系 (2)以下关于 SessionFactory 的说法哪些正确?(多选) A)对于每个数据库事务,应该创建一个 SessionFactory 对象 B)一个 SessionFactory 对象对应一个数据库存储源。 C)SessionFactory 是重量级的对象,不应该随意创建。如果系统中只有一个数据库存储源,只需要创建一个。 D)SessionFactory 的 load()方法用于加载持久化对象 (3)Customer 类中有一个 Set 类型的 orders 属性,用来存放 Order 订单对象,在 Customer.hbm.xml 文件中,用哪个元素映射 orders 属性? A) B) C) D) (4)元素有一个 cascade 属性,如果希望 Hibernate 级联保存集合中的对象,casecade 属性应该取什么值?(单选) A)none B)save C)delete D)save-update (5)以下哪些属于 Session 的方法? A)load() B)save() C)delete() D)update() E)open() F)close() (6)以下程序的打印结果是什么?(单选) tx = session.beginTransaction(); Customer c1=(Customer)session.load(Customer.class,new Long(1)); Customer c2=(Customer)session.load(Customer.class,new Long(1)); System.out.println(c1==c2); tx.commit(); session.close(); A)运行出错,抛出异常 B)打印 false C)打印 true (7)以下程序代码对 Customer 的 name 属性修改了两次: tx = session.beginTransaction(); Customer customer=(Customer)session.load(Customer.class, new Long(1)); customer.setName(\"Jack\"); customer.setName(\"Mike\"); tx.commit(); 执行以上程序,Hibernate 需要向数据库提交几条 update 语句?(单选) A)0 B)1 C)2 D)3 (8)在持久化层,对象分为哪些状态?(多选) A)临时状态 B)独立状态 C)游离状态 D)持久化状态 (9)对于以下程序,Customer 对象在第几行变为持久化状态?(单选) Customer customer=new Customer(); //line1 customer.setName(\"Tom\"); //line2 Session session1=sessionFactory.openSession(); //line3 Transaction tx1 = session1.beginTransaction(); //line4 session1.save(customer); //line4 tx1.commit(); //line5 session1.close(); //line6 A) line1 B)line2 C)line3 D)line4 E)line5 F)line6 (10)对于以下程序,Customer 对象在第几行变为游离状态?(单选) Customer customer=new Customer(); //line1 customer.setName(\"Tom\"); //line2 Session session1=sessionFactory.openSession(); //line3 Transaction tx1 = session1.beginTransaction(); //line4 session1.save(customer); //line4 tx1.commit(); //line5 session1.close(); //line6 A) line1 B)line2 C)line3 D)line4 E)line5 F)line6 (11)以下哪一种检索策略利用了外连结查询?(单选) A)立即检索 B)延迟检索 C)迫切左外连结检索 (12)假设对 Customer 类的 orders 集合采用延迟检索策略,编译或运行以下程序,会出现什么情况(单选) Session session=sessionFactory.openSession(); tx = session.beginTransaction(); Customer customer=(Customer)session.get(Customer.class,new Long(1)); tx.commit(); session.close(); Iterator orderIterator=customer.getOrders().iterator(); A)编译出错 B)编译通过,并正常运行 C)编译通过,但运行时抛出异常 (13)关于 HQL 与 SQL,以下哪些说法正确?(多选) A)HQL 与 SQL 没什么差别 B)HQL 面向对象,而 SQL 操纵关系数据库 C)在 HQL 与 SQL 中,都包含 select,insert,update,delete 语句 D)HQL 仅用于查询数据,不支持 insert,update 和 delete 语句 (14)事务隔离级别是由谁实现的?(单选) A)Java 应用程序 B)Hibernate C)数据库系统 D)JDBC 驱动程序 (15)悲观锁与乐观锁,哪个具有较好的并发性能?(单选) A)悲观锁 B)乐观锁 答案: (1)A,B,C (2)B,C (3)A (4)D (5)A,B,C,D,F (6)C (7)B (8)A,C,D (9)D (10)F (11)C (12)C (13)B,D (14)C (15)B hibernate 中为什么一定要事务? Hibernate 是对 JDBC 的轻量级对象封装, Hibernate 本身是不具备事务处理功能的,Hibernate 事务实际上是底层的 JDBC 事务的封装, 只不过在 Hibernate 中,session 打开的时候,就会自动 conn.setAutoCommit(false),不像一般的 JDBC,JDBC 默认都是 true,所以 用 Hibernate 的时候,你在程序中不写 Transaction 的话,数据库根本就没有反应。 ======================================spring==================================== 为什么要用 spring spring 是一个轻量级的框架。具有依赖注入/反转控制功能:还有 AOP 面向方面编程。 你在项目中用到了 xml 技术的哪些方面?如何实现的? 答:用到了数据存贮,信息配置两方面。采用开源包 jdom 或 dom4j 实现的。 什么是重量级?什么是轻量级? 轻量级是指它的创建和销毁不需要消耗太多的资源,意味着可以在程序中经常创建和销毁 session 的对象; 重量级意味不能随意的创建和销毁它的实例,会占用很多的资源 写出你熟悉的开源框架以及各自的作用。 答:框架:hibernate、spring、struts; Hibernate 主要用于数据持久化; spring 做控制的。 struts 主要用于控制页面跳转。 Spring 两大特性是什么? 依赖注入/反向控制(IoC)和面向切面编程(AOP)是 Spring 框架的两大特性. 什么是依赖注入/反向控制:(Dependency Injection 、IOC) 就是程序之间的调用关系由容器来控制的,原来我们是由代码直接控制的。这样做层次清晰,耦合度小。 依赖注入和反向控制是一个意思。就是原来由程序员写代码完成层次之间的调用。现在由 spring 容器根据配置文凭来负责调用关系。 反过来了,所以也叫反向控制。 主要是运用了 java 的反射机制。通过 spring 的配置文件,把相互依赖的关系配置好。 主要有 set 注入 , annotation 注解注入 我们项目中采用 Resource 注解注入(按 bean 的名字注入)。Autoware 按类型注入。 Aop: 面向方面(切面)编程:AOP 不是一种技术,而是编程思想。 简单地说,就是将那些与业务无关,但是业务模块中要用到的公共代码封装起来,减少重复代码,降低模块间的耦合度,便于维护。 我们 spring 中的事务控制就是利用 AOP 原理来实现的。底层是通过动态代理设计模式来实现的。 动态代理的本质通常就是对目标对象的方法进行拦截,加入自己的处理,spring 中的事务控制就是在调用前启动事务,调用后提交事务, 最后关闭 session。这些重复的工作由 spring 来完成。 切面还可以这样来理解: Spring 框架的组成? Spring 框架有七个模块组成组成,这 7 个模块(或组件)均可以单独存在,也可以与其它一个或多个模块联合使用,主要功能表现如下: 1: Spring 核心容器(Core):提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。 BeanFactory 使用控制反转(Ioc)模式将应用程序的配置和依赖性规范与实际的应用代码程序分开。 2: Spring AOP:主要是进行事务管理,面向方面(切面)编程。 3: Spring ORM:Spring 框架集成了 Hibernate 的关系对象映射。 4: Spring DAO: 提供 JdbcTemplate(jdbc 面板)封装了对数据库的操作 5: Spring WEB:Spring 框架集成了 struts。利用了 jsp 和 struts 的标签库 6: Spring 上下文(Context): Spring 上下文是一个配置文件(applicationContext.xml),向 Spring 框架提供上下文信息。 7: Spring MVC:Spring 框架集成了 struts 进行页面跳转。 spring 如何获取 Bean? ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml"); context.getBean(“beanName”); spring 中使用了什么设计模式? 1: 观察者模式 Spring 中提供了一种事件监听机制,即 ApplicationListener(应用程序监听器),可以实现 Spring 容器内的事件监听 2: 单列模式 spring 默认将所有的 bean 设置成单态模式,因此可大大降低 Java 对象在创建和销毁时的系统开销。 3:工厂模式:Spring 使用配置文件管理所有的 bean ,其配置文件中 bean 由 Spring 工厂负责生成和管理。。 4:模板方法模式: jdbcTemplate .update("delete from TB_USER where ID= 466 "); 只需要一句代码, 就完成了我们关心的 jdbc 操作(具体 jdbc 操作在内部实现) (Update 方法里是调用了其他类来完成的。 Spring 是使用 Java 接口回调实现的。 5:动态代理:spring 中的事务控制就是用了动态代理 Action3 控制层 Services3 层 Dao3 层 Action2 控制层 Services2 层 Dao2 层 Action1 控制 层 Services1 层 Dao1 层 上 下 层 是 调 用 关 系 横向关系看成一个切面 Dao 层:里面有好多的代码都是重复的。 这样对于这个 dao 层这个切面。可以通过动态代理的机制将 重复代码让 spring 容器来完成。减少程序员 重复的代码量。如事务的处理。 开启事务, 提交事务, 关闭 session struts+Spring+hibernate 工作流程图: 1: JSP 页面提交请求到 struts 的 ActionServlet 核心控制器 2: struts 容器根据配置文件找到对应的 Action, 在 action 中调用 spring 注入的 bean 进行业务处理 3: spring 注入的 bean 再调用 DAO(hibernate)进行数据库的操作 4: 操作结果数据返回到 Action 再由 Action 定位到具体的 JSP 显示结果。 spring 事务的传播行为 在类前加上@Transactional,声明这个类的所有方法需要事务管理。每一个业务方法开始时都会打开一个事务。 Spring 默认情况下会对运行期异常(RunTimeException)进行事务回滚。如果遇到 checked 异常就不回滚。 Java 中:RuntimeException(unchecked 异常) 与 checkedException 的差别? Error 与 RuntimeException 则被统称为 Unchecked Exception(未检查异常不需要处理的) 除此之外是 checked(已检查异常需要处理 的) RuntimeException 体系包括错误的类型异常、算术异常,类型不匹配异常,数组越界异常,空指针异常等等。一定是程序员的错误。 Runtime exceptions: 在定义方法时不需要声明会抛出 runtime exception; 在调用这个方法时不需要捕获这个 runtime exception; runtime exception 是从 java.lang.RuntimeException 或 java.lang.Error 类衍生出来的。 其他继承自 java.lang.Exception 得异常统称为 Checked Exception。 Checked exceptions: 定义方法时必须声明所有可能会抛出的 checked exception; 如:public boolean add() throws HibernateException; 界面显示 输入控制 持久层 ORM 对象模型与关系模型的一个映射 调用 hibernate 的 api 进行操作 Action 的作用:页面导航 在调用这个方法时,必须捕获它的异常。 例如: public clalss Test{ public void fun(){ int i=10/0;} 这是运行时异常:也就是属于(unchecked 异常)调用时不用捕捉。 public void fun1() throws HibernateException{ .................................. throw new HibernateException(“我是 checked 异常”); } public static void main(String args[]){ new Test().fun(); 这个异常程序员不用捕获 try{ new Test().fun1(); 这个异常程序员需要捕获 }catch(Exception ex){ex.printStackTrace();} } 如何改变默认规则: 1 让 checked 例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class) 2 让 unchecked 例外不回滚: @Transactional(notRollbackFor=RunTimeException.class) 3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED) 在整个方法运行前就不会开启事务 还可以加上:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true),这样就做成一个只读事务,可以提高 效率。 3: Spring 中事务传播行为种类: Spring 在 TransactionDefinition 接口中规定了 7 种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务 如何进行传播: PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,就加入到这个事务中融为一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED 类似的操作。 ============================================================================== 总结如下:对于查询统一为: @Transactional(propagation=Propagation.NOT_SUPPORTED, readOnly=true) 对于增加删除修改统一为: @Transactional(propagation=Propagation. REQUIRED ,rollbackFor=Exception.class) 最好写在类的上面。针对整个类的所有的方法进行事务。 ============================================================================== 使用 spring 有什么好处(优点)? (1)Spring 有依赖注入、反转控制功能。能有效地组织中间层对象。 (2)Spring 帮我们搞定单列设计模式。 (3)Spring 配置清晰。 (4)Spring 面向接口编程。 (5)在 Spring 应用中的大多数业务对象没有依赖于 Spring。 (6 Spring 本身是一个轻量级容器,Spring 的组件就是普通的 Java Bean,构建的应用程序易于单元测试。 (7)Spring 支持 JDBC 和 O/R Mapping 产品(Hibernate) (8)Spring 能使用 AOP 提供声明性事务管理,能帮我们搞定事务处理。 ===============================hibernate+spring 结合中====================== SessionFactory. getCurrentSession 与 openSession 的区别 1. openSession 每次都打开一个连接,需要关闭。getCurrentSession ()在上下文中找旧的 session 如果没有找到就新建一个。 2. 使用 SessionFactory. getCurrentSession ()时,Hibernate 会从 CurrentSessionContext 接口中获取当前的 Session, CurrentSessionContext 有三个实现,分别是 ThreadLocalSessionContext、JTASessionContext 和 ManagedSessionContext。 需要在 hibernate.cfg.xml 中如下配置: 如果采用 jdbc 独立引用程序配置如下:即借助于数据库的事务:本地事务 thread :设定 session 的上下文 如果采用了 JTA 事务配置如下:即分布式事务(跨数据库使用) jta :设定 session 的上下文 如: 在做 ssh 项目中你 过 session 被关闭吗? 答:在 ssh 框架中我们用 getCurrentSession()获取 session,此时的 session 由 spring 容器管理,自动关闭的. 如果手动 session.close() .会报 session 已经关闭。 ================================数据库====================================== DML(数据操纵语言)它们是、update、insert, delete DDL(据定义语言 )它们是:create、alter、drop 等 Oracle 的内置用户: 用户名称:sys 默认密码:change_on_install 超级用户。是一个唯一能访问特定内部数据字典的用户。 用户名称:system 默认密码:manager 用于 DBA 任务的管理。 用户名称:scott 默认密码:tiger 普通用户。下面有一些表。我们可以做测试用 Oracle 的内置角色: 3 种标准角色(oracle 已经定义好了的角色) 1.connect role(连接角色) 2. resource Role(资源角色) 3. DBA Role(数据库管理员角色) 结论: 对于普通用户:授予 connect, resource 权限。 对于 DBA 管理用户:授予 dba 权限。 一、 什么是事务 通俗的理解,事务是一组原子操作单元,从数据库角度说,就是一组 SQL 指令,要么全部执行成功,若因为某个原因其中一条指令执行有 错误,则撤销先前执行过的所有指令。更简答的说就是:要么全部执行成功,要么撤销不执行。 事务必须服从 ACID 原则 ACID 即:事务的原子性、一致性、独立性及持久性 事务的原子性是指一个事务要么全部执行,要么不执行 事务的一致性是指事务的运行并不改变数据库中数据的一致性.例如,完整性约束了 a+b=10,一个事务改变了 a,那么 b 也应该随之改变. 事务的独立性是指两个以上的事务不会出现交错执行的状态.因为这样可能会导致数据不一致. 事务的持久性是指事务运行成功以后,就系统的更新是永久的.不会无缘无故的回滚. Java 事务的类型 Java 事务的类型有三种:JDBC 事务、JTA(Java Transaction API)事务、容器事务。 1、JDBC 事务(也称为本地事务) JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。 java.sql.Connection 提供了以下控制事务的方法: public void setAutoCommit(boolean) public boolean getAutoCommit() public void commit() public void rollback() JDBC 事务的一个缺点是事务的范围局限于一个数据库连接。一个 JDBC 事务不能跨越多个数据库。 2、JTA (Java Transaction API)事务(分布式事务) JTA 事务可以跨多个数据库。 3、容器事务 (自动事务) 容器事务主要是 J2EE 应用服务器提供的,容器事务大多是基于 JTA 完成,就像 spring 管理 hibernate 事务一样,不要程序员来写。 用在 EJB 程序中 三种事务差异 1、JDBC 事务控制的局限性在一个数据库连接内,但是其使用简单。 2、JTA 事务的功能强大,事务可以跨越多个数据库或多个 DAO,使用也比较复杂。 3、容器事务,主要指的是 J2EE 应用服务器提供的事务管理,局限于 EJB 应用使用。 事务控制总结 一般说来,在单个 JDBC 连接连接的情况下可以选择 JDBC 事务,在跨多个连接或者数据库情况下, 需要选择使用 JTA 事务,如果用到了 EJB,则可以考虑使用 EJB 容器事务。 如何优化数据库的性能? 第一:数据库调整: a:对该表的查询频率比较高,则建立索引 ,减少表的间关联。 ( 建立索引时,想尽对该表的所有查询搜索操作, 按照 where 选择条件建立索引,但是索引不可太多) b: 多表操作时:使用存储过程 ,查询时可以使用视图。 c:简化或避免对大型表进行重复的排序。 d:避免相关子查询 查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉 尽可能多的行。 e:使用临时表加速查询 。 f:查询时大表在前小表在后,效力最高。where 子句中的连接顺序,以过滤掉最大数量记录的条件必须写在 where 子句的末尾. g: 正确的 sql 语句 因此在书写应用程序的 SQL 的 where 子句时,注意以下几种情况: 1: 避免使用不兼容的数据类型. 2: 避免对搜索参数使用其它数学操作符,。 select name from emplyee where salary * 10 > 30000  select name from emplyee where salary > 3000 3: 避免使用!=或<>等这样的操作符,因为这会使系统无法使用索引,而只能直接搜索表中的数据. 4: 在查询时,不要过多地使用通配符如 select * 语句;尽量不要在应用中使用数据库游标,游标是非常有用的工具。但比 SQL 语句需要更大的开销. 第二: 硬件调整: 扩大虚拟内存,并保证有足够可以扩充的空间;把数据库服务器上的不必要服务关闭掉 把数据库服务器和主域服务器分开 把 SQL 数据库服务器的吞吐量调为最大 在具有一个以上处理器的机器上运行 SQL. 如何提高数据库并发性能?(答标题:里面的细节了解能用自己的话讲) 1 :细粒度锁表 减少大事物操作 (一个包含很多 SQL 语句、牵涉很多表的大事物操作锁住的资源也会多); 尽量不使用表级排他锁,而是用行级锁;又因为锁一般是由数据库根据你的 SQL 自动分配,所以要注意 SQL 2 :拆表 2.1 物理拆分方式 水平拆分: 把不同记录分开放进不同表中。如短信:有普通短信,彩信,长短信 可以分别放在不同的表中。 垂直拆分: 把不同列分别放入不同表中。比如主用户信息放入一张表,附加信息放入另一张表。 混合拆分(水平拆分+垂直拆分) 2.2 逻辑拆分方式:对于大数据量的表建立表分区 如:一个省的电话费用信息。可以将话费表,按照地市 ID 建立分区。不同地市的数据存在不同的分区上。 3 :多数据源(多库) 本质是拆库。与拆表异曲同工。 4 :乐观锁 可以降低数据库长事物。只在提交的那一刹那判断自己提交的数据是否已经被别人修改过了,如果是的则取消提交,否则,提交成功。 避免长事物带来的等待。通常采用版本号来判断是否过期数据。 5 :采用临时表 使用局部临时表提高并发性能。局部临时表特点是多用户操作互不干扰。一个局部临时表只对一个 session 可见、有效。多用户并发实际 是各操作各自的临时表,不会产生数据表锁的问题。提高并发效率。 把主表(频繁使用又数据量大)中的部分数据放入局部临时表,然后在临时表里进行计算、统计等工作,然后同步到主表中去(同步过程 可用乐观锁机制),减少了主表在并发时锁等待的开销。 临时表性能提升原理和拆分表原理相同:通过把一个大集合拆成小集合,然后在小集合上进行计算。 6 :采用缓存机制:如 hibernate 的缓存机制。 7 :数据库集群。 与多库(拆库)有区别的: 集群是每个库上都有一份相同的数据;拆库是每个库只有全集的部分数据。 多数据库冗余可以减少单个数据库的负载,总体上提高了性能。它有 3 个技术关键点: 数据库查询路由 数据库同步 负载均衡算法 8 :读写分离策略(当 sql 优化不能达到效果的时候可以考虑) 读写分离简单的说是把对数据库读和写的操作分开对应不同的数据库服务器,这样能有效地减轻数据库压力,也能减轻 io 压力。主数据库 提供写操作,从数据库提供读操作,其实在很多系统中,主要是读的操作。当主数据库进行写操作时,数据要同步到从的数据库,这样才 能有效保证数据库完整性。 9 :SQL 优化 10 :正确使用索引: 表的要求:对于大数据量的表,主要是查询的表(增加删除修改少)的表。 列的要求:重复内容比较少的列,多表连接时,用于连接的列,设置索引。 6.3 程序设计中如何考虑系统的安全性? 1: 防 SQL 注入式攻击 SQL 注入式攻击是指在输入框或 URL 中输入 SQL 语句,绕过验证程序,非法获取用户的访问权,进行非法操作的入侵方式。 防御 SQL 注入式攻击的方法常用两种, 1:一种是使用数据库管理系统的存储过程, 2:另一种是对表单输入的信息进行校验,从查询变量中过滤去尽可能多的可疑字符。 3:使用 PreparedStatement 代替 Statement. 2:双重验证 (前后台验证,数据加密) 客户端的验证可以提高与用户的交互性,主要是采用 javascript 也就是前台实现。 服务器端的验证保证数据的安全性。 主要是类代码来实现。也就是后台实现。 3:非法链接和非法复制 1:采用禁止使用右击功能,防止不懂计算机的用户可以,稍有计算机知识的人都很容易地获取信息。因此,可以对一些字做图片字典, 当信息中包含这些字时,使用图片显示,用户非法复制后的内容将不是完整的内容。 4:防盗链 采用 Servlet 过滤器或者拦截器对所有的请求进行过滤。如果用户没有登录则他的信息在 session 中没有保存信息, 通过判断 session 中的信息是否为 null, 重定向到登录页面。 5: 数据库安全管理 A:采用表空间,给用户授权,给表授权,给表的字段授权。 B:视图的使用 通过视图可以指定用户使用数据的范围,将用户限定在表中的特定字段或表中的特定记录,并且视图和基础表一样也可以作为授权的单 位。针对不同用户的视图,在授权给一用户的视图中不包括那些不允许访问的机密数据,从而提高了系统的安全性。 C: 定期进行必要的数据备份. 6: 部署安全性 将所有 jsp 放到 WEB-INF 目录下或其子目录下。WEB-INF 是应用服务器的安全目录,用户是无法通过 url 的方式访问到该目录下的任 何内容的。但是服务器端的程序可以访问它们. 7: 定期对服务器进行安全检查 服务器是对外开放的 防止病毒,即时下载服务器补丁程序。 安装一个功能强大的防火墙可以有效防御外界对 Web 服务器的攻击,同时应限制非法用户对网络的访问,规定具有特定 IP 地址的客户机 对本地网络服务器的访问权限,以防止从外界对网络服务器配置的非法修改。 1、关于 delete、truncate、drop 相同:truncate,不带 where 子句的 delete,drop 都会删除表内的数据 不同: 1. truncate 和 delete 只删除数据不删除表的结构 drop 语句将删除表的结构被依赖的约束,触发器,索引 2. delete 是 dml,可以回滚,事务提交后生效 truncate,drop 是 ddl, 操作立即生效,不能回滚 3. 删除部分数据使用 delete(附带 where 语句) 删除表内全部数据可以用 delete(速度慢,可以恢复)或 truncate(速度快,不能恢复) 删除整个表,用 drop 4. delete 不影响表原显患用的区,truncate 释放区到 minextents 数量,drop 语句将表所占用的空间全部释放 truncate 语句执行速度快,占资源少,并且只记录要删除的日志; delete 对每条记录的删除均需要记录日志 ==================oracle 数据库备份与恢复数据导出:(oracle 的备份方式)================== 在已经安装了 oracle 数据库的 dos 窗口中运行命令: 1:将数据库 myoracle 完全导出,用户名 system 密码 manager 导出到 D:\daochu.dmp 中 exp system/manager@myoracle file=d:\daochu.dmp full=y 2:将数据库中 system 用户与 sys 用户的表导出 exp system/manager@myoracle file=d:\daochu.dmp owner=(system,sys) 3:将数据库中的表 table1 、table2 导出 exp system/manager@myoracle file=d:\daochu.dmp tables=(table1,table2) 4:将 D:\daochu.dmp 中的数据导入 myoracle 数据库中。 imp system/manager@TEST file=d:\daochu.dmp 上面可能有点问题,因为有的表已经存在,然后它就报错,对该表就不进行导入。 在后面加上 ignore=y 就可以了。 5:将 d:\daochu.dmp 中的表 table1 导入 imp system/manager@myoracle file=d:\daochu.dmp tables=(table1) 6:删除同其他表相同的行:删除 a 表中 id 与 b 表的 id 相同的值的数据 delete from a where id in (select id from b); 7:删除重复行:该表没有主键:有重复的行 delete from a where rowid!= (select max(rowid) from a b where a.id=b.id) 8:复制一张表 create table new_tab as select * from old_tab where 1= 1 数据也过去了 create table new_tab as select * from old_tab where 1= 2 空表 1.存储过程和函数的区别 存储过程没有返回类型,只有输入输出参数,而函数有返回类型, 向调用者返回数据。 2. 游标的作用?如何知道游标已经到了最后? 游标用于定位结果集的行。通过游标的属性可以知道:游标%notfoud 就知道到了最后 3. 触发器分为事前触发和事后触发,这两种触发有何区别。语句级触发和行级触发有何区别。 事件发生之后触发就是事后触发,事件发生之前触发就是事前触发。 before 触发器可以获取新值(:new.字段)和老值(:old.字段)。 语句级触发器只触发一次,而行级触发器:影响多少条数据就触发多少次. 4:什么是视图? 视图相当于创建的一张虚拟表。用户可以像操作普通表一样操作视图。视图往往不占用数据库额外的存储空间,而只存储定义。 5:什么是基本表?什么是视图?两者的区别和联系是什么? 基本表是独立存储的数据表。视图是存储数据库中的预先定义好的查询,具有基本表的外观 理存储空间。区别: 6:什么是存储过程? 存储过程是数据库的一个对象,由 PL/SQL 代码组成保存在数据库中,应用程序可以调用,可以定义输入和输出参数。能够处理复杂的业 务逻辑。安全性能好,效率高(只编译一次而 sql 语句每次都要编译) 7:什么是触发器? 触发器是一种特殊类型的存储过程, 触发器主要通过事件触发执行的。有语句级触发器和行级触发器。 Sqlserver 的分页语句:利用的是 TOP select top 页大小 * from table1 where id < ( select isnull(min(id),0) from ( select top 页大小*(页数-1) id from table1 order by id desc ) a ) 如:第一页: select top 10 * from table1 where id > ( select isnull(max(id),0) from ( select top 0 id from table1 order by id ) a ) order by id Mysql 的分页 SQL: 利用的是:limit select * form table limit 0,10 就是从第 0 条开始到第 10 条! oracle 的分页 SQL: 利用的是:行号 rownum select * from (select * from (select my_table.*, rownum as my_rownum from ( select * from 表 where 1 = 1 order by id desc ) my_table where rownum < 2) where my_rownum > 0) 默认的端口号: Oracle: 1521 Sqlserver 1433 Mysql 3066 Tomcat 8080 jboss 1099 weblogic 7001 数据库建表的原则:======遵循数据库的三范式============================================= 简单描述: 第三范式的要求如下: 1,每一列只有一个值 2,每一行都能区分。 3,每一个表都不包含其他表已经包含的非主关键字信息。 第一范式(1NF): 表中无表 例如: 在存储一个学生的信息:包挂 学生的名字, 学生的性别, 学生的年龄 如果建一张 people 表:将学生的所有信息存入一个字段则如下: 此时业务要求:查询 id 号等于 1 的学生性别: 这个就不好查询 如果将表修改如下:则查询学生的任何信息都方便。 下面的就是符合第一范式。 第二范式(2NF): 没有部分函数依赖 以学生和课程为例: 需求:学生的信息, 课程信息,学生的成绩要进行存取。 如果用一张表来存取:student 学号 姓名 成绩 课程名称, 总学分 001 张三 50 数学 100 001 张三 70 语文 100 001 张三 60 外语 100 002 李四 90 数学 100 002 李四 70 语文 100 002 李四 50 外语 100 那么该表的关键字:必须是组合关键字(学号,课程名称) 才能决定某个同学的某门课程的成绩 例如:查询学号是 001 的语文成绩: Select 成绩 from student where id=001 and 课程名称=’语文’ 需要两个字段(学号,课程名称)来决定。 这个数据库表不满足第二范式,因为存在如下决定关系: 根据课程名称就能知道该门功课的 总学分 。 课程名称---------------- 总学分 根据学号就能知道学生的姓名。 学号---------------- 姓名 不满足第二范式:即存在组合关键字中的字段决定非关键字的情况。 由于不符合 2NF,这个选课关系表会存在如下问题: id name Sex age 1 张三 男 25 (1) 数据冗余: 同一门课程由 n 个学生选修,"学分"就重复 n-1 次;同一个学生选修了 m 门课程,姓名和年龄就重复了 m-1 次。 (2) 更新异常: 若调整了某门课程的学分,数据表中所有行的"学分"值都要更新,否则会出现同一门课程学分不同的情况。 (3) 插入异常: 假设要开设一门新的课程,暂时还没有人选修。这样,由于还没有"学号"关键字,课程名称和学分也无法 记录入数据库。 (4) 删除异常: 假设一批学生已经完成课程的选修,这些选修记录就应该从数据库表中删除。但是,与此同时,课程名称 和学分信息也被删除了。很显然,这也会导致删除异常。 把学生表 student 改为如下三个表: 学生表 课程表 学号_id 姓名 1 张三 2 李四 课程_id 课程名称, 总学分 1 数学 100 2 语文 100 3 外语 100 选 课 关 系 表: 学号_id 课程_id, 成绩 1 1 50 1 2 70 1 3 60 2 1 90 2 2 70 2 3 50 select 姓名, 课程名称,总学分,成绩 from 学生表 s ,课程表 c ,选课关系表 k where s,学号_id=k.学号_id and c.课程_id=k.课程_id 这样的数据库表是符合第二范式的,消除了数据冗余、更新异常、插入异常和删除异常。 第三范式(3NF):在第二范式的基础上,非传递函数依赖: 关键字段 → 非关键字段 x → 非关键字段 y 需求:学生的信息, 学生所在学校的信息要进行存取。如果放到一张表中。 学号_id 姓名 年龄 学院名称 学院地点 学院电话 001 张三 30 理工学院 奇家岭 84848844 002 李四 38 民族学院 郭镇 84848666 003 王五 46 职业学院 郭镇东部 84848777 004 张三三 50 理工学院 奇家岭 84848844 005 李四四 30 理工学院 奇家岭 84848844 006 王五五 28 理工学院 奇家岭 84848844 学号_id 为该表的关键字:存在如下决定关系: (学号) ------》 (学院名称) ------》(学院地点, 学院电话) 它也会存在数据冗余、更新异常、插入异常和删除异常的情况,读者可自行分析得知。 参照主表 参照主表 改进如下: 把学生关系表分为如下两个表: 学生表:(学号, 姓名, 年龄, 学院名称); 学院表:(学院 Id,学院, 地点, 电话)。 学生表: 学号 姓名 年龄 学院 id 001 张三 30 1 002 李四 38 2 003 王五 46 3 学院表: 学院 ID 学院名称 学院地点 学院电话 1 理工学院 奇家岭 84848844 2 民族学院 郭镇 84848666 3 职业学院 郭镇东部 84848777 这样的数据库表是符合第三范式的,消除了数据冗余、更新异常、插入异常和删除异常。 ================================关系数据模型==================================== 在关系模型中,每一个关系都是一个二维表。 关系数据模型包括那几个方面 关系数据模型包括(关系数据结构)、( 关系完整性约束)和(关系运算)三个方面 授课思路:以部门表和人员表说明主外键的关键。说明关系的完整性,以及关系运算。结合 deveplor 讲解。 并且讲解主外键关系。建模思路。级联操作。 查询:人员情况以及部门情况: 关系的完整性主要包括域完整性、实体完整性和参照完整性三种。 1.域完整性:属性的取值范围 域完整性是对数据表中字段属性的约束,它包括字段的值域、字段的类型及字段的有效规则等约束,它是由确定关系结构时所定义 的字段的属性决定的。 如:一张人员表中不想姓名是张三的人员插入:可以再 name 字段上增加约束: 当数据表中插入名字为张三的记录时,会报错. 2.实体完整性:要有唯一主键值 实体完整性是对关系中的记录唯一性,也就是主键的约束。准确地说,实体完整性是指关系中的主属性值不能为 Null 且不能有相同 值。 下面增加一条记录时,因为主键字段 id 插入的是重复的值:2 所有报错。该为非 2 的值就可以了。 3.参照完整性::即要么没有外键,要么外键是其他表实际存在的主键值:如成绩表的学生 id 字段值。 学生表: 学生 id 姓名 001 张三 002 李四 003 王五 成绩表 ===============数据库的事务=====数据库并发控制=========== 一、 什么是事务 通俗的理解,事务是一组原子操作单元,从数据库角度说,就是一组 SQL 指令,要么全部执行成功,若因为某个原因其中一条指令执行有 错误,则撤销先前执行过的所有指令。更简答的说就是:要么全部执行成功,要么撤销不执行。 事务必须服从 ACID 原则 ACID 即:事务的原子性、一致性、独立性及持久性 事务的原子性是指一个事务要么全部执行,要么不执行 事务的一致性是指事务的运行并不改变数据库中数据的一致性.例如,完整性约束了 a+b=10,一个事务改变了 a,那么 b 也应该随之改变. 事务的独立性是指两个以上的事务不会出现交错执行的状态.因为这样可能会导致数据不一致. 事务的持久性是指事务运行成功以后,就系统的更新是永久的.不会无缘无故的回滚. 多用户数据库系统的存在 允许多个用户同时使用的数据库系统 飞机定票数据库系统 银行数据库系统 特点:在同一时刻并发运行的事务数可达数百个 课程 Id 课程名字 分数 学生 id 1 数学 45 001 2 历史 56 001 不同的多事务执行方式 (1)事务串行执行 . 每个时刻只有一个事务运行,其他事务必须等到这个事务结束以后方能运行 . 不能充分利用系统资源,发挥数据库共享资源的特点 (2)交叉并发方式(Interleaved Concurrency) 在单处理机系统中,事务的并行执行是这些并行事务的并行操作轮流交叉运行 单处理机系统中的并行事务并没有真正地并行运行,但能够减少处理机的空闲时间,提高系统的效率 (3)同时并发方式(simultaneous concurrency) 多处理机系统中,每个处理机可以运行一个事务,多个处理机可以同时运行多个事务, 实现多个事务真正的并行运行  事务并发执行带来的问题 . 会产生多个事务同时存取同一数据的情况 . 可能会存取和存储不正确的数据,破坏事务一致性和数据库的一致性 事务并发可能发生的事情 第一类丢失更新 撤销一个事务会影响到另外一个事务:造成另一个事务的数据丢失 时间 取款事务 A 转账事务 B T1 开始事务 T2 开始事务 T3 查询余额为 700 T4 查询账户余额为 700 元 汇入 200 将余额改为 900 T5 提交事务 commit T6 取出 100 元把余额改为 600 元 T7 撤销事务:rollback T8 余额恢复为 700 元(丢失更新) T9 第二类丢失更新 一个事务覆盖另外一个事务已经提交的数据,造成 B 事务所做操作丢失 时间 转账事务 A 取款事务 B T1 开始事务 T2 开始事务 T3 查询账户余额为 1000 元 T4 查询账户余额为 1000 元 T5 取出 100 元把余额改为 900 元 T6 提交事务 T7 汇入 100 元 T8 提交事务 T9 把余额改为 1100 元(丢失更新) 不可重复读: 一个事务范围内两个相同的查询却返回了不同的数据。主要针对修改操作 时间 转账事务 A 取款事务 B T1 开始事务 T2 开始事务 T3 查询账户余额为 1000 元 T4 查询账户余额为 1000 元 T5 取出 100 元把余额改为 900 元 T6 T7 查询账户余额为 900 元 T8 撤销事务: 将账户余额恢复到 1000 元 T9 一个事务里面读了两次:两次读取的数 据不一致:不知道按 1000 还是按 900 处理 不可重复读" 是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么, 在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这 样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。例如,一个编辑人员两次读取同一文 档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果 只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题 幻读:主要是针对插入和删除的操作:一个事务内两次读取的记录的条数不一样 时间 转账事务 A 取款事务 B T1 开始事务 T2 开始事务 T3 插入一个学生 T4 查询学生总数 为 400 人 T5 提交事务 T6 T7 再次查询学生总数 为 401 人 T8 T9 一个事务里面读了两次:两次读取的数 据不一致:不知道按 400 还是按 401 处理 幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表 中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发 生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。 例如,一个编辑人员更改作者提交的文档,另外一个人将新材料合并到新提交的文档中,此时编辑人员发现原来改完 了文档,出现了新的未改的如是产生了幻觉。如果在编辑人员编辑完文档之前,任何人都不能将新材料添加到文档中, 则可以避免该问题。 幻读和不可重复读区别:主要是针对插入和删除的操作 为了确保并发用户在存取同一数据库对象时的正确性(即无丢失修改、可重复读、不读“脏”数据),数据库中引入了 锁机制。数据库就是通过锁机制来解决并发问题的。 并发控制的主要技术 有封锁(Locking) 时间戳(Timestamp) 乐观控制法 商用的 DBMS 一般都采用封锁方法  基本封锁类型 . 排它锁(Exclusive Locks,简记为 X 锁) . 共享锁(Share Locks,简记为 S 锁) 从数据库系统的角度来看锁的类型和兼容性 共享锁 l 加锁条件:当一个事务执行 select 语句时,数据库系统会为这个事务分配一把共享锁,锁定被查询的数据. l 解锁条件:数据被读取后,数据库系统立即解除共享锁. l 与其它锁的兼容性:如果数据资源上放置了共享锁,还能再放置共享锁和更新锁. l 并发性能:良好的并发性能.当多个事务读相同数据时,每个事务都会获得一把共享锁,可以同时读锁定的数据. 独占锁也叫排它锁 加锁条件:当一个事务执行 insert,update,delete 时,数据库系统会自动对 SQL 语句操纵的数据资源使用独占锁.如果该数据资源已经有其它 锁存在时,无法对其再放置独占锁. 解锁条件:独占锁一直到事务结束后才能被解除. 与其它锁的兼容性: 独占锁不能和其他锁兼容,单独存在。 并发性能:并发性能较差, 它锁定的资源,其他事务不能读取也不能修改。 什么是并发调度的可串行性: 通常是指不管数据库初态处于什么状态,一个调度对数据库状态的影响都和某个串行调度相同,我们就说这个调度是可串行化,称 之为可串行调度。 例如:现在有两个事务,分别进行下列操作: 事务 A: 存 100 元 事务 B: 存 500 元 张山 300 串行化调度: 时间 存款事务 A 存款事务 B T1 开始事务 T2 Slock B 对张山的资金加上一个共享锁 T3 查询账号余额是 300 元 T4 Unlock B 释放共享锁 T5 Xlock B T6 存入 100 将余额改为 400 T7 提交事务:commit 写数据到数据库 T8 Unlock B T9 开始事务 T10 获得 Slock B : 对张山的资金加上一个共享锁 T11 查询余额为 400 T12 Unlock B T13 Xlock B T14 汇入 500 将余额改为 900 提交事务 commit Unlock B 假定:金额字段 用 B 表示 不可串行化的调度 时间 存款事务 A 存款事务 B T1 开始事务 开始事务 T2 Slock B 对张山的资金加上一个共享锁 Slock B : 对张山的资金加上一个共享锁 T3 查询账号余额是 300 元 查询余额为 300 T4 Unlock B 释放共享锁 Unlock B T5 T6 T7 Xlock B T8 存入 100 将余额改为 400 T9 提交事务:commit 写数据到数据库 T10 Unlock B T11 Xlock B T12 汇入 500 将余额改为 800 T13 提交事务 commit T14 Unlock B 可串行化调度 时间 存款事务 A 存款事务 B T1 开始事务 T2 Slock B 对张山的资金加上一个共享锁 T3 查询账号余额是 300 元 T4 Unlock B 释放共享锁 开始事务 T5 Slock B : 对张山的资金加上一个共享锁 T6 T7 Xlock B 等待 T8 存入 100 将余额改为 400 等待 T9 提交事务:commit 写数据到数据库 等待 T10 Unlock B 等待 T11 查询余额为 400 等存款事务 A 提交了,再读 T12 Unlock B T13 汇入 500 将余额改为 800 T14 提交事务 commit Unlock B 两段锁协议:实现并发调度的可串行性保证调度的正确性。 两段锁协议是指每个事务的执行可以分为两个阶段:生长阶段(加锁阶段)和衰退阶段(解锁阶段)。 加锁阶段:在该阶段可以进行加锁操作。在对任何数据进行读操作之前要申请并获得 S 锁,在进行写操作之前要申请并获得 X 锁。加锁不 成功,则事务进入等待状态,直到加锁成功才继续执行。 解锁阶段:当事务释放了一个封锁以后,事务进入解锁阶段,在该阶段只能进行解锁操作不能再进行加锁操作。 两段封锁法可以这样来实现:事务开始后就处于加锁阶段,一直到执行 rollback 和 commit 之前都是加锁阶段。rollback 和 commit 使 事务进入解锁阶段,即在 rollback 和 commit 模块中 dbms 释放所有封锁。 多粒度封锁协议 多粒度封锁协议允许多粒树中的每个结点被独立加锁。对一个结点加锁意味着这个结点的所有后裔结点也被加以同样类型的锁。 锁的粒度: 三级粒度树: 显示封锁:直接加到数据对象上的锁 隐式封锁:由于上级节点的加锁,而使数据对象上加的锁。 例如:事务 1 对该表的第三条记录加了排它锁(写锁) 如事务 2 要对该表加排它锁(写锁)则必须逐一检查每条记录。是否己加了不相 容的锁。由于事务 1 给第三条记录加了排它锁。事务 2 就不能对表加排它锁了。 但是事务 2 花费了很多时间来查询每条记录的锁。事务 2 有没有办法,在给表加锁时不必检查每条记录。就知道能不能加锁呢? 意向锁可以解决这个问题。 意向锁:是放置在资源层次结构的一个级别上的锁,以保护较低级别资源上的共享或排它锁 意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁; 对任一结点加锁时,必须先对它的上层结点加意向锁。 例如,对任一条记录加锁时,必须先对它所在的表加意向锁。 例如,事务 1 对该表的第一条记录加了排它锁(写锁),则在该表上放置意向锁(排它锁)事务 2 试图在该表上加意向锁(排它锁)时, 则受到事务 1 控制的表级别意向锁的阻塞。 意向锁的分类: IS 锁:如果对一个 数据对象加 IS 锁,表示它的后裔结点拟(意向)加 S 锁。例如,要对某个元组加 S 锁,则要首先对表和数据库 加 IS 锁。 IX 锁:如果对一个 数据对象加 IX 锁,表示它的后裔结点拟(意向)加 X 锁。例如,要对某个元组加 X 锁,则要首先对表和数据 库加 IX 锁。 SIX 锁:如果对一个 数据对象加 SIX 锁,表示对它加 S 锁,再加 IX 锁,即 SIX=S+IX。例如对某个表加 SIX 锁,则表示该事务要 读整个表(所以要对该表加 S 锁),同时会更新个别元组(所以要对该表加 IX 锁)。 具有意向锁的多粒度封锁方法提高了系统的并发度,减少了加锁和解锁的开销,它己经在实际的 数据库管理系统产品中得到广泛应用,例 如新版的 Oracle 数据库系统就采用了这种封锁方法。 数据库锁 表级锁 行级锁 使用封锁机制解决丢失修改问题 假定有个一个账户表:有一条记录是张山的存钱数目 800。两个事务同时操作。 时间 取款事务 存款事务 T1 开始事务 T2 Xlock A: 在读金额数据修改之前先对金额数据加 X 锁 开始事务:对金额数据加锁 :此时加写锁被拒绝 T3 查询账号余额是 800 元 等待 T4 取出 100 将余额改为 700 等待 T5 提交事务:commit 等待 T6 Unlock A 等待 获得 Xlock A T7 查询余额为 700 T8 汇入 200 将余额改为 900 T9 提交事务 commit T10 Unlock A 使用封锁机制解决不可重复读问题 时间 查询余额事务 存款事务 T1 开始事务 T2 Slock A: 在读金额数据之前先对金额数据加 S 锁 开始事务:对金额数据加写锁 :此时加写锁被拒绝 T3 查询账号余额是 800 元 等待 T4 等待 T5 等待 T6 再次查询账号余额也是 800 等待 等待 T7 Unlock A 等待 T8 获得 Xlock A(写锁) T9 查询余额为 700 T10 汇入 200 将余额改为 900 提交事务 commit Unlock A 使用封锁机制解决读“脏”数据问题 时间 取款事务 存款事务 T1 开始事务 T2 Xlock A: 在读金额数据之前先对金额数据加 X 锁 开始事务:对金额数据加锁 :此时加锁被拒绝 T3 查询账号余额是 800 元 等待 T4 等待 T5 取出 100 元修改余额为 700 等待 T6 Rollback 回滚, 恢复余额为 800 等待 张山 800 等待 T7 Unlock A 等待 T8 获得 Xlock A(写锁) T9 查询余额为 800 T10 汇入 200 将余额改为 1000 提交事务 commit Unlock A 锁粒度:一般分为:行级锁、表级锁、库级锁 并发问题的解决方案 事务隔离级别是并发控制的整体解决方案,其实际上是综合利用各种类型的锁和行版本控制,来解决并发问题。 锁是数据库并发控制的内部机制,是基础。不适当的设置锁,可能会导致严重的阻塞和死锁。建议,只有在完全了解锁 机制的情况下,才可以在语句中手动设置锁,否则应该使用事务隔离级别。为了避免上面出现的丢失更新,脏读,不 可重复读,幻读几种情况,在标准 SQL 规范中,定义了 4 个事务隔离级别, 不同的隔离级别对事务的处理不同。 事务隔离级别:一个事务对数据库的修改与并行的另一个事务的隔离程度。隔离级别与并发性是互为矛盾的:隔离程 度越高,数据库的并发性越差;隔离程度越低,数据库的并发性越好。 ANSI/ISO SQL92 标准定义了一些数据库操作的隔离级别: 1:未提交读(read uncommitted)语句级别 (隔离级别最低,并发性能高) 2:提交读(read committed) 语句级别 (锁定正在读取的行) 3:可重复读(repeatable read) 事务级别 (锁定所读取的所有行) 4:序列化(serializable) 事务级别 (锁表) 最高隔离级别。系统中所有的事务都是一个接一个执行的。因此也就不会发生任何事务之间的冲突问题 Oracle 中的隔离级别及实现机制: Oracle 共支持 3 种事务隔离级别: 1. Serializable(锁表)  最高的隔离级别,串行执行事务,并发性最小,就是使事务看起来象是一个接着一个地顺序地执行。  保证不会出现非重复读和幻读,脏读。 2. read committed  这是 ORACE 缺省的事务隔离级别。  保证不会脏读;但可能出现非重复读和幻读。 Oracle 在修改数据记录时,会把这些记录被修改之前的结果存入回滚段或撤销段中,如果一个事务正在对某个表 进行 DML 操作,而这时另外一个会话对这个表的记录进行读取操作,则 Oracle 会去读取回滚段或撤销段中存放的 更新之前的记录,而不会象 SQL Server 一样等待更新事务的结束 3. read only 遵从事务级的读一致性,只能查询到已经提交的数据。 不允许在本事务中进行:插入、修改、删除操作。 read ony 是 seriaizabe 的子集。它们都避免了非重复读和幻读。区别是在 read ony 中是只读;而在 seriaizabe 中可以进行插入、修改、删除操作。 四、 乐观锁与悲观锁:应用程序可以釆用悲观锁或乐观锁来控制。 数据库一般的默认隔离离级别是”读已提交”,默认的事务隔离级别下:Insert,update ,delete 下的是 X 锁(排它锁), 会等待事务完成。通常情况下可以把隔离级别设为 Read Commited,能避免脏读,而且有较好的并发性能。尽管它会导 致不可重复读、虚读和第二类更新丢失等问题,在可能出现这类问题的个别场合可以由应用程序釆用悲观锁或乐观锁 来控制。 悲观锁【Pessimistic Locking】 采用一种悲观的态度来对待事务并发问题,悲观锁的基本思想就是每次一个事务读取某一条记录后,就会把这条记录 锁住,这样其它的事务要想更新,必须等以前的事务提交或者回滚解除锁。 那么通过悲观锁,能控制了不可重复读的问题,但是不能避免幻读的问题,如果想避免幻读问题,那么你只能依靠数 据库的 serializable 隔离级别(幸运的是幻读问题一般情况下不严重)。 悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能 真正保证数据访问的排他性,否则, 即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。 乐观锁【Optimistic Locking】 它的基本思想就是每次提交一个事务更新时,我们想看看要修改的东西从上次读取以后有没有被其它事务修改过,如 果修改过,那么更新就会失败。(因此能够解决第二类丢失修改问题)。 因为乐观锁其实并不会锁定任何记录,所以如果我们数据库的事务隔离级别设置为读取已提交或者更低的隔离界别, 那么是不能避免不可重复读问题的(因为此时读事务不会阻塞其它事务),所以采用乐观锁的时候,系统应该要容许不 可重复读问题的出现。 Tomcat 如何优化? 调优方案分类: 1,外部环境调优 2,自身调优 外部环境调优如下: 1:对 JAVA 虚拟机进行优化:加大 JAVA 虚拟机的内存。 java 虚拟机可使用的最大内存是有限制的,缺省值通常为 64MB 或 128MB。 如果一个应用程序为了提高性能而把数据加载内存中而占用较大的内存,比如超过了默认的最大值 128MB,需要加大 java 虚拟机可使用 的最大内存,否则会出现 Out of Memory(系统内存不足)的异常。 java -Xms128m -Xmx256m … 表示 java 虚拟机初始化时使用的内存为 128MB,可使用的最大内存为 256MB。 Tomcat 需要依赖 Java 虚拟机运行,虚拟机可通过命令行方式改变虚拟机使用内存的大小。 tomcat 默认可以使用的内存为 128MB,在较大型的应用项目中,这点内存是不够的,需要调大。 Windows 下,在文件 tomcat_home/bin/Catalina.bat 中增加 JAVA_OPTS=’-Xms256m –Xmx512m’这表示初始化内存为 256MB, 可以使用的最大内存为 512MB。我们一般把-Xms 和-Xmx 设置一样大,值为可用最大内存的 80%。 Unix 下,在文件{tomcat_home}/bin/catalina.sh 的前面,增加如下设置: JAVA_OPTS='-Xms【初始化内存大小】 -Xmx【可以使用的最大内存】' 需要把这个两个参数值调大。 自身调优如下: 1. 加大 tomcat 并发数(线程数) 在 tomcat 配置文件 server.xml 中的配置中,和连接数相关的参数有: maxThreads : tomcat 起动的最大线程数,即同时处理的任务个数,默认值为 200。 minProcessors:最小空闲连接线程数,用于提高系统处理性能,默认值为 10 。 maxProcessors:最大连接线程数,即:并发处理的最大请求数,默认值为 75 。 acceptCount: 当 tomcat 起动的线程数达到最大时,接受排队的请求个数,默认值为 100。 minSpareThreads :Tomcat 初始化时创建的线程数。 maxSpareThreads :一旦创建的线程超过这个值,Tomcat 就会关闭不再需要的 socket 线程。 connectionTimeout:网络连接超时,单位:毫秒。设置为 0 表示永不超时,这样设置有隐患的。通常可设置为 30000 毫秒。 其中和最大连接数相关的参数为 maxProcessors 和 acceptCount。如果要加大并发连接数,应同时加大这两个参数。 2:禁用 DNS(域名)查询 当 web 应用程序向要记录客户端的信息时,它也会记录客户端的 IP 地址或者通过域名服务器查找机器名转换为 IP 地址。DNS 查询需要 占用网络,并且包括可能从很多很远的服务器或者不起作用的服务器上去获取对应的 IP 的过程,这样会消耗一定的时间。为了消除 DNS 查询对性能的影响我们可以关闭 DNS 查询,方式是修改 server.xml 文件中的 enableLookups 参数值: ========================类之间的关系================================ 类与类之间存在以下关系: (1)泛化(Generalization) (2)关联(Association) (3)依赖(Dependency) (4)聚合(Aggregation) 1.泛化(Generalization) [泛化] 表示类与类之间的继承关系,接口与接口之间的继承关系,或类对接口的实现关系。一般化的关系是从子类指向父类 的,与继承或实现的方法相反。 [具体表现] 父类 父类实例=new 子类() (泛化)类对接口的实现关系 简要的写法: (泛化)类与类之间的继承关系 (泛化)接口与接口之间的继承关系 2.依赖(Dependency) [依赖] 对于两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者依赖另一个对象的服务时,这两个对象之间 主要体现为依赖关系。 [具体表现] 依赖关系表现在局部变量,方法的参数, 方法的返回值的类型 以及对静态方法的调用 [现实例子] 病人看病,你是不是要借助(也就是依赖)医生来帮助你完成看病的工作 public class 病人{ /** 看病 */ public void 看病(医生 obj){ obj.看病(); //这种情况成为耦合 } } 类 A 依赖与类 B、类 C、类 D,类 E public class A{ public B getB(C c, D d){ 类 A 中方法实例化类 E :局部变量 E e = new E(); } } 静态方法的调用: public class a{ public static void fun(){} } public class b { public void fun2(){a.fun();} } 关联(Association) [关联] 对于两个相对独立的对象,当一个对象的实例与另一个对象的一些特定实例存在固定的对应关系时,这两个对象之间 为关联关系。 [具体表现] 关联关系是使用实例变量来实现 public class Company{ private List employee; //类对象做成员 ……………. } 聚合(Aggregation) [聚合] 当对象 A 被加入到对象 B 中,成为对象 B 的组成部分时,对象 B 和对象 A 之间为聚集关系。聚合是关联关系的一种, 是较强的关联关系,强调的是整体与部分之间的关系。 [具体表现] 与关联关系一样,聚合关系也是通过实例变量来实现这样关系的。关联关系和聚合关系来语法上是没办法区分的,从 语义上才能更好的区分两者的区别。 聚合 :整体和部分关系 组合关系: 皮之不存,毛将覆焉 接口的实现关系: 接口实现关系的简化形式 人事面试知识 1、为什么要选择我们公司? 在网上看到贵公司的招聘然后就去看了一些公司评价和发展觉得公司的情况挺不错,然后自己又符合招聘要求所以就过来了。 2、如果你和上级意见不同你会怎么做? 首先如果我觉得我的是正确的我会坚持自己的一件,不过我和经理交流的时候一定会注意方式方法,毕竟他考虑问题的范围更大一下, 我会私下里和他去好好交流这些问题 如果他一直坚持的自己是正确的,那个我会保留意见,选择执行,公司的制度还是应该执行下去这样效率才最高 3、上家公司的离职原因? 原来我是在长沙的一家公司,毕业之后老师介绍去的,然后的话在那边工作情况还可以,就是离家太远了回一趟家太麻烦了,所以现在 想在机会更多离家更近的北京发展。 还有一些比较好的朋友也在这边所以自己也想过来。 4、公司录用你的原因? 我所学的东西是公司招聘上所需要的,也就是我能给公司创造价值,并且我也乐于实现自己的价值。 5、你的优点? 我感觉自己和别人交流的人能力还是不错的,交流过程中我能学习到很多的东西。喜欢去思考怎么把所学转化成所用,学习能力还可以。 你的缺点? 做事比较着急,不喜欢吧事情拖着,然后的话还有就是生活上不是很注意细节。 6、你的职业规划? 我感觉做 IT 行业每个程序员都应该有个成为大牛的梦想吧,我自己也是,感觉慢慢的从基础做起慢慢的找准一个方向去学精,去学通。 价值上面,我感觉自己还是一个挺有理想的一个人吧,自己做的事情我想做好,也希望在公司学到更多的东西,希望和公司一起成长, 我觉得这种感觉一定很好! 7、最近看了什么书? 是一本有关 jvm 优化的书,看了没有多少,平时也喜欢在论坛啊博客上看一些新技术,自己也喜欢敲一些小例子。 8、对加班有什么看? 首先我不认同加班,我觉得自己能够在有限时间完成自己的工作,所以对自己的加班也就没有什么必要了。 不过我知道 IT 行业的话,公司项目上线的时候,有时候是需要一些在加班的,这些我是可以接受的,我觉得也是有必要的。 注意点:1、自我介绍 可以介绍一下自己在哪里读的书,为什么离职,平时爱好,做过的项目,熟悉的框架,表现出自己的自学能力 2、介绍项目的时候准备一个自己会遇到的问题,他常会问你遇到过什么问题 3、谈工资的时候,他问你工资的时候,你问他公司什么样的福利福利好了就低点,谈工资不要谈物价 谈自己的价值 4、还有讲话的时候不要表现出自己不稳定,就说之前谈过几个还不错的公司都有回应。 5、还有最好不要说自己又男女朋友,因为这也会成为自己的不稳定因素,公司会考虑你会不会因为女朋友区别的地方 6、他问你想对公司还有什么疑问么? 你可以问,公司主要做哪方面的。用的什么技术,还有可以问下公司会有加薪的情况么? 公司的发展怎么样 7、注意在技术面试的时候尽量吧他往你自己熟悉的地方带
还剩41页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 3 人已下载

下载pdf

pdf贡献者

linsen

贡献于2018-01-02

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf