目录
一、缓存
1.mybatis一级缓存
2.mybatis二级缓存
开启二级缓存
二、Java反射机制概念
1.Java反射概念
2.Java反射相关api
三、Java反射相关类
1.Class类(反射基础)
(1)Object类中的getClass方法:适用于通过对象获得Class实例的情况
(2)类名.class方式:适用于通过类名获得Class实例的情况
(3)Class类的静态方法 forName(String name)
2.Constructor类(获得构造方法)
3.Field类(获得属性)
4.Method类(获得方法)
四、反射优缺点
一、缓存
数据缓存使数据离我们执行程序更近,让程序能快速获得数据。有了缓存之后,我们查询数据会先从缓存中查询,缓存没有数据再去数据库。查到后将数据放到缓存中,以便下次快速查询到数据,提高数据库性能。
1.mybatis一级缓存
在参数和 SQL 完全一样的情况下,我们使用同一个 SqlSession 对象调用一个 Mapper 方法,往往只执行一次 SQL。
因为使用 SqlSession 第一次查询后,MyBatis 会将其放在缓存中。以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession 都会取出当前缓存的数据,而不会再次发送 SQL 到数据库。
这里我们以一个教师表为例,通过id查询教师信息
一级缓存的作用域是同一个 SqlSession。在同一个 sqlSession 中两次执行相同的 sql 语句。第一次执行完毕会将数据库中查询的数据写到缓存(内存)。第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession 结束后该sqlSession 中的一级缓存也就不存在了。Mybatis 默认开启一级缓存。
具体流程如下图:
一级缓存生命周期:
开始于SqlSession创建
结束于SqlSession关闭,如果期间执行了增删改操作也会清空SqlSession对象中缓存数据。
调用sqlSession.clearCache();强制清空一级缓存数据
2.mybatis二级缓存
二级缓存是SqlSessionFactory级别的,可以让多个SqlSession共享数据。mybatis默认不开二级缓存,需手动配置
开启二级缓存后,SqlSession关闭后,会将一级缓存数据传到二级缓存,这时,其他SqlSession就可以从二级缓存查数据。
二级缓存是多个 SqlSession 共享的,其作用域是同一个 namespace。不同的sqlSession 两次执行相同 namespace 下的 sql 语句且向 sql 中传递参数也相同即最终执行相同的 sql 语句第一次执行完毕会将数据库中查询的数据写到缓存(内存)。第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis 默认没有开启二级缓存需要在 setting 全局参数中配置开启二级缓存。
注:sqlSession 执行 insert、update、delete 等操作 commit 提交后会清空缓存区域,防止脏读
具体流程如下图:
开启二级缓存
(1)在.xml配置文件中添加以下标签:value值true为开始,false为关闭
<setting name="cacheEnabled" value="true"/>
(2)给所有使用的模型类实现序列化接口 Java.io. Serializable。
(3)在写sql语句的Mapper映射文件中添加<cache />,表示此 mapper 开启二级缓存。
<!--flushInterval二级缓存关闭时间-->
<cache flushInterval="60000"></cache>
查询结果如下:
二、Java反射机制概念
在之前的文章中,我为大家介绍的java基础知识通常建立在已知类名、属性,方法等等。但在最近接触了有关框架的知识后,我们发现在实际开发中,像框架、组件,他们通常要接收任何类型的类,而且只知道传进去的类的类名。这样我们该如何动态的获取类中的信息呢?这就不得不介绍Java的反射机制了。
1.Java反射概念
JAVA反射机制是在运行状态中,对于任意一个类,只知道类名便可获取这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
2.Java反射相关api
● Java反射相关的类主要包括• Class 类型• Constructor 构造方法• Method 方法• Field 属性• 除了Class外,其他类都位于java.lang.reflect包中● 可见,反射API将类的类型、方法、属性都封装成了类,其中最重要的类是Class,可以说,反射的使用都是从Class开始。
三、Java反射相关类
以下演示中Object类暂由临时创建的User类代替!!!
1.Class类(反射基础)
● 一旦class文件被加载到内存,就会为其创建一个Class对象。任何类被使用时都会创建一个Class对象。● Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息。
获得一个类的Class类的实例方式:
(1)Object类中的getClass方法:适用于通过对象获得Class实例的情况
//创建一个User类,通过对象user得到Class实例
User user = new User();
Class clayy = user.getClass();
(2)类名.class方式:适用于通过类名获得Class实例的情况
Class claxx = User.class;
(3)Class类的静态方法 forName(String name)
//classname用来接收User类路径
String classname = "com.javareflect.User";
Class clazz = Class.forName(classname);
补充:还可以通过Class类对象,创建对象
//classname用来接收User类路径
String classname = "com.javareflect.User";
Class clazz = Class.forName(classname);
Object object1 = class1.newInstance();//newInstance(Object... initargs):创建实例
2.Constructor类(获得构造方法)
Constructor实例通过Class实例获得。
Constructor类可以通过getXXX方法获得构造方法的基本信息
Class类中定义了方法,如:
Constructor<T> getConstructor(Class... parameterTypes) :通过指定参数类型,返回构造方法实例。newInstance(Object... initargs):创建实例
● getConstructor(Class...parameterTypes) | 获得指定的公共构造方法 |
● getConstructors(Class...parameterTypes) | 获得所有的公共构造方法 |
● getDeclaredConstructor(Class...parameterTypes) | 获得指定的构造方法(不建议) |
● getDeclaredConstructors(Class...parameterTypes) | 获得所有的构造方法(不建议) |
注:一般不建议动私有方法,轻易操作私有属性,打破了封装性。
String classname = "com.javareflect.User";
//1.获得类的Class对象
Class class1 = Class.forName(classname);
//2通过类的Class对象,创建对象
Object object1 = class1.newInstance();
//获得类的构造方法,通过构造方法api中的方法创建对象
Constructor constructor = class1.getConstructor();//获得指定的公共构造方法
Object object2 = constructor.newInstance();//创建对象
//有参构造,String类型
Constructor constructor1 = class1.getConstructor(String.class,String.class);
Object object3 = constructor1.newInstance("adsd","111");
Constructor [] constructors = class1.getConstructors();//获得所有公共构造方法
class1.getDeclaredConstructor();//获得类中任意构造方法,包括私有
class1.getDeclaredConstructors();//获得类中所以构造方法,包括私有
3.Field类(获得属性)
Field类将类的属性进行封装,可以获得属性的基本信息、属性的值,也可以对属性进行赋值.public Field getField(String name):通过指定Field名字,返回Field实例.● getName:返回属性的名字● set:设置属性值
getField(String name)
| 获得指定的公共成员变量 |
getDeclaredField(String name) | 获得指定的成员变量,含私有 |
getFields() | 获得所有的公共成员变量 |
getDeclaredFields() | 获得所有的成员变量,含私有 |
注:set()方法可以给getDeclaredField获得的属性赋值,一般不建议动私有方法,轻易操作私有属性,打破了封装性。
String classname = "com.javareflect.User";
Class class1 = Class.forName(classname);
Object object1 = class1.newInstance();
//模拟从数据库查到数据,现在封装到类中
HashMap<String,String> map = new HashMap<>();
map.put("account","admin");
map.put("password","1111");
Field[] declaredFields = class1.getDeclaredFields();//依次获得类中所有成员变量
for (Field field:declaredFields){
field.setAccessible(true);
//getName拿到类中属性的名称,map.get通过getName传进来的键get到相应的值
field.set(object1,map.get(field.getName()));
}
System.out.println(object1);
这里只是演示field的作用,实际开发中绝对不建议操作私有属性 !!!
4.Method类(获得方法)
Method getMethod(String name, Class... parameterTypes) :通过指定方法名,参数类型,返回一个Method实例● getName:获得方法名字● getParameterTypes:获得方法参数类型
String classname = "com.javareflect.User";
Class class1 = Class.forName(classname);
Object object1 = class1.newInstance();
//获得类中的方法
Method method = class1.getMethod("eat");
//调用访问
method.invoke(object1);
调用了User类中的eat()方法
四、反射优缺点
优点:● 1.增加程序的灵活性,可以在运行的过程中动态对类进行修改和操作● 2.提高代码的复用率,比如动态代理● 3.可以在运行时轻松获取任意一个类的方法、属性,并且还能通过反射进行动态调用
缺点:● 1.反射会涉及到动态类型的解析,导致性能要比非反射调用更低● 2.使用反射技术通常要在一个没有安全限制的程序运行 .● 3.反射可以绕过一些限制访问的属性或者方法,可能会导致破坏代码本身的抽象性