day17-反射-事务
来源:互联网 发布:男友那个很大 知乎 编辑:程序博客网 时间:2024/06/03 19:02
反射
反射的目的:为了操作某个类的属性或方法
反射能够获得: 1.类的构造器 2.属性 3. 方法
类的加载器将class文件加载到虚拟机中(内存中),那么有一个Class对象(代表是class文件加载到内存后所形成的一个对象)
第一步:获得Class对象(3种办法),
第二步:获得不同参数个数的各个构造器, 就可以对应创建类的实例了.
第三步:获得操作类中的属性.
第四步:获得类中的方法
反射的详细的执行过程(4步)
* 获得代表这个类加载到内存的字节码文件的对象Class对象.
public void demo1() throwsClassNotFoundException{
// 一种:通过类名.class
Classclazz1 = Person.class;
// 二种:通过类的实例对象.getClass()方法获得.
Personperson =new Person();
Classclazz2 =person.getClass();
// 三种:使用Class的forName的静态方法获得.(推荐使用这种)
Classclazz3 = Class.forName("com.itheima.demo3.reflect.Person");
}
* 通过反射操作其构造方法:
* DBUtils: Person person = queryRunner.query(sql,newBeanHanlder(Person.class));
public void demo2() throws Exception{
// 反射第一步获得Class对象.
Classclazz = Class.forName("com.itheima.demo3.reflect.Person");
// 采用默认的无参数的构造方法创建:
// Personperson = (Person) clazz.newInstance();
//person.run();
// 采用有参数的构造方法来创建对象:Person p = new Person("张森",38);
Constructorc =clazz.getConstructor(String.class,Integer.class);
Personp = (Person)c.newInstance("张森",38);
System.out.println(p.name);
System.out.println(p.age);
}
* 通过反射获得类中的属性:
public void demo3() throws Exception{
// 反射第一步获得Class对象.
Classclazz = Class.forName("com.itheima.demo3.reflect.Person");
// 获得属性:
// 以下两种仅仅获得共有的属性:
//clazz.getField("name"); //获得某个属性
// Field[]fields = clazz.getFields(); //获得所有属性
// 获得私有的属性: p.name =对象.属性
Fieldfield1 =clazz.getDeclaredField("name");
field1.setAccessible(true);
Fieldfield2 =clazz.getDeclaredField("age");
field2.setAccessible(true);
Constructorc =clazz.getConstructor(String.class,Integer.class);
Personp = (Person)c.newInstance("张森",42);
Stringname = (String)field1.get(p);
Integerage = (Integer)field2.get(p);
System.out.println(name+" "+age);
}
* 通过反射获得类中的方法:并且让方法执行.
public void demo4() throws Exception{
// 反射第一步获得Class对象.
Classclazz = Class.forName("com.itheima.demo3.reflect.Person");
// 获得类中的方法:
Methodmethod =clazz.getDeclaredMethod("run");
method.setAccessible(true);
method.invoke(clazz.newInstance());// p.run();
// 获得带有参数的方法:
Methodmethod2 =clazz.getDeclaredMethod("sayHello", String.class);
Strings = (String)method2.invoke(clazz.newInstance(),"凤姐");// String s =p.sayHello("凤姐");
System.out.println(s);
}
内省: 用来获得JavaBean的属性及属性的get或set方法.
内省的代码:
* 获得某个类中的属性:
* * 一个JavaBean属性由get或set方法确定的
public void demo1() throws Exception{
// 获得了Bean的信息
BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
// 获得Bean的属性描述了 属性描述器
PropertyDescriptor[] pds =beanInfo.getPropertyDescriptors();
for(PropertyDescriptorpd:pds){
System.out.println(pd.getName());
/*pd.getReadMethod(); //获得这个属性对应的get方法
pd.getWriteMethod();//获得这个属性对应的set方法.
使用内省来写一个,对数据进行封装的工具类
public class MyBeanUtils {
public static void populate(Object obj,Map<String,String[]> map) throws Exception{
// 获得类的所有的属性的名称:
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
// 获得类中所有的属性:
PropertyDescriptor[] pds =beanInfo.getPropertyDescriptors();
for (PropertyDescriptorpd : pds) {
if(map.containsKey(pd.getName())){
Method method =pd.getWriteMethod();
// 执行set方法:
method.invoke(obj,map.get(pd.getName())[0]);
}
}读到map中与属性名相同的key时,将value存入属性的值,完成封装
事务(数据安全)
JDBC (Spring事务更重要)
特性/隔离级别
MYSQL的事务管理有两种方式:
(MYSQL数据库事务默认是自动提交的.Oracle数据库事务默认是不自动提交.)
* 1.手动开启事务
* start transaction; -- 开启事务
* 多条sql;
* commit/rollback;
* 2.设置一个自动提交参数
* show variables like '%commit%'; -- 查看与commit相关参数.
* set autocommit = 0; -- 将autocommit参数设置为OFF.
【JDBC中的事务管理】(掌握)
JDBC的事务的管理的API:
事务得加在业务层,因为事务必须由同一个Connection管理才能起作用.
即必须由一个Connection管理多个事务,将service层中的Connection传递给dao的多个方法.
* 事务管理的第一种办法发:向下传递Connection:
*业务层转账的方法:
public voidtransfer1(String from, Stringto, Double money) {
AccountDaoaccountDao =new AccountDao();
// 方式一:在业务层获得Connection,传递给DAO。
Connectionconn =null;
try {
conn = JDBCUtils.getConnection();
conn.setAutoCommit(false);
//accountDao.outMoney(conn,from,money);
intd = 1/ 0;
//accountDao.inMoney(conn,to,money);
conn.commit();
}catch (Exceptione) {
try {
conn.rollback();
}catch (SQLExceptione1) {
e1.printStackTrace();
}
e.printStackTrace();
}
public class JDBCUtils {
private static finalComboPooledDataSourceDATA_SOURCE =newComboPooledDataSource();
* 获得连接的方法
public static ConnectiongetConnection(){
Connectionconn =null;
try {
conn =DATA_SOURCE.getConnection();
}catch (SQLExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}
returnconn;
}
public static DataSourcegetDataSource(){
returnDATA_SOURCE;
}
* 事务管理的第二种方法:绑定到当前线程
* 业务层转账的方法:
public voidtransfer2(String from, Stringto, Double money) {
AccountDaoaccountDao =new AccountDao();
// 方式二:
try {
JDBCUtils2.beginTransaction();
创建连接并将连接与当前线程绑定 ,然后将事务设为手动提交
//accountDao.outMoney(from,money);
intd = 1/ 0;
//accountDao.inMoney(to,money);
JDBCUtils2.commitTransaction();
}catch (Exceptione) {
try {
JDBCUtils2.rollBackTransaction();
}catch (SQLExceptione1) {
e1.printStackTrace();
}
e.printStackTrace();
}
public class JDBCUtils2 {
private static finalComboPooledDataSourceDATA_SOURCE =newComboPooledDataSource();
privatestaticfinalThreadLocal<Connection>tl = newThreadLocal<Connection>();
* 获得连接的方法
public static ConnectiongetConnection(){
Connectionconn =null;
try {
conn =tl.get();
if(conn ==null){
conn = DATA_SOURCE.getConnection();
tl.set(conn);
}
}catch (SQLExceptione) {
// TODOAuto-generated catch block
e.printStackTrace();
}
returnconn;
}
public static voidbeginTransaction() throws SQLException{
Connectionconn =null;
conn = tl.get();
if(conn ==null){
conn =DATA_SOURCE.getConnection();
tl.set(conn);
}
conn.setAutoCommit(false);
}
public static voidcommitTransaction()throws SQLException{
Connectionconn =tl.get();
conn.commit();
}
public static voidrollBackTransaction()throws SQLException{
Connectionconn =tl.get();
conn.rollback();
}
public static DataSourcegetDataSource(){
returnDATA_SOURCE;
}
事务管理的第三种方法:使用DBUtils进行事务的管理:
public void transfer(Stringfrom, Stringto, Double money) {
AccountDaoaccountDao =new AccountDao();
Connectionconn = JDBCUtils.getConnection();
try {
conn.setAutoCommit(false);
accountDao.outMoney(conn,from ,money);
intd = 1/ 0;
accountDao.inMoney(conn,to,money);
DbUtils.commitAndCloseQuietly(conn);
}catch (Exceptione) {
DbUtils.rollbackAndCloseQuietly(conn);
e.printStackTrace();
}
事务特性:
原子性:强调事务的不可分割.
一致性:强调的是事务的执行的前后,数据的完整性要保持一致.
隔离性:一个事务的执行不应该受到其他事务的干扰.
持久性:事务一旦结束(提交/回滚)数据就持久保持到了数据库.
如果不考虑事务的隔离性,引发一些安全性问题:
一边的操作影响到另外一边的操作,引发的问题.
读问题:
* 脏读 :一个事务读到另一个事务还没有提交的数据.
* 不可重复读 :一个事务读到了另一个事务已经提交的update的数据,导致在当前的事务中多次查询结果不一致. (一个事务里面读到两个不同的结果)
* 虚读/幻读 :一个事务读到另一个事务已经提交的insert的数据,导致在当前的事务中多次的查询结果不一致.
写问题:
* 引发两类丢失更新:
解决引发的读问题:
设置事务的隔离级别:
* read uncommitted :脏读,不可重复读,虚读都可能发生.
* read committed :可以避免脏读. 但是不可重复读和虚读有可能发生.
* repeatable read :可以避免脏读,不可重复读. 但是虚读有可能发生.
* serializable :可以避免脏读,不可重复读,虚读的发生.(安全性提升的同时性能降低)
MYSQL默认隔离级别:repeatable read ; Oracle隔离级别:read committed
设置窗口的隔离级别为:read uncommitted:
set session transaction isolation level read uncommitted;
查看窗口的隔离级别:select @@tx_isolation;
演示脏读的发生:
分别开启两个窗口:A,B
分别查看两个窗口的隔离级别:select @@tx_isolation;
设置A窗口的隔离级别为:read uncommitted:
* set sessiontransaction isolation level read uncommitted;
分别在两个窗口中开启事务:
* start transaction;
在B窗口完成转账的操作:
* update account setmoney = money - 1000 where name = '张森';
* update account setmoney = money + 1000 where name = '凤姐';
在A窗口查询数据:(钱已经到账---脏读)
* select * fromaccount; -- A事务读到了B事务还没有提交的数据.
演示避免脏读,不可重复读发生
分别开启两个窗口:A,B
分别查看两个窗口的隔离级别:select @@tx_isolation;
设置A窗口的隔离级别为:read committed:
* set sessiontransaction isolation level read committed;
分别在两个窗口中开启事务:
* start transaction;
在B窗口完成转账的操作:
* update account setmoney = money - 1000 where name = '张森';
* update account setmoney = money + 1000 where name = '凤姐';
在A窗口中进行查询:
* select * fromaccount; -- 避免脏读.
在B窗口提交事务:
* commit;
在A窗口中再次查询:
* select * fromaccount; -- 转账成功.(不可重复读:一个事务读到另一个事务中已经提交的update的数据,导致多次查询结果不一致.)
演示避免不可重复读:
分别开启两个窗口:A,B
分别查看两个窗口的隔离级别:select @@tx_isolation;
设置A窗口的隔离级别为:repeatable read:
* set sessiontransaction isolation level repeatable read;
分别在两个窗口中开启事务:
* start transaction;
在B窗口完成转账的操作:
* update account set money = money - 1000where name = '张森';
* update account set money = money + 1000where name = '凤姐';
在A窗口查询:
* select * from account; -- 转账没有成功:避免脏读.
在B窗口提交事务:
* commit;
在A窗口中再次查询:
* select * from account; -- 转账没有成功:避免不可重复读.
演示避免虚读的发生:
分别开启两个窗口:A,B
分别查看两个窗口的隔离级别:select @@tx_isolation;
设置A窗口的隔离级别为:serializable:
* set sessiontransaction isolation level serializable;
在A,B两个窗口中分别开启事务:
* start transaction;
在B窗口中完成一个insert操作:
* insert into account values (null,'王老师',10000);
在A创建中进行查询的操作:
* select * from account; -- 没有查询到任何结果.
在B窗口提交事务:
* commit; -- A窗口马上就会显示数据.
MVC和EE的三层结构:
- day17-反射-事务
- day17
- day17
- day17
- Day17
- Day17
- day17
- DAY17
- Day17
- 事务&MVC&反射
- day13-事务&mvc&反射补充
- day17-笔记
- Day17对话框
- Day17:weekend
- Day17-request
- day17笔记
- Python-day17
- day17笔记
- 图论day4(最小花费/刻录光盘)
- Python ::OS模块 提供的接口介绍
- Tablayout + viewpager
- 逆序的三位数
- 算法练习(2)—— 简单分治
- day17-反射-事务
- 20170917Hive学习总结
- Java transient关键字使用小记
- 解密
- 面向对象 接口和多态
- dispatch_barrier_async和dispatch_barrier_sync的区别在哪呢?
- 超速判断
- JSP页面日期按格式显示!
- JS的原始值和复杂值