java懒加载
发布时间:2025-05-23 22:27:25 发布人:远客网络
一、java懒加载
java前台如何取消懒加载
默认是当前用户id@主机名,所以极有可能是root@localhost哦,至于你这样发出去,会不会被别人家的邮件服务器当垃圾拒收,俺就不随意猜测了。但这样,默认也不方便回复邮件啊,所以还是设置设置吧。
默认是当前用户id@主机名,所以极有可能是root@localhost哦,至于你这样发出去,会不会被别人家的邮件服务器当垃圾拒收,俺就不随意猜测了。但这样,默认也不方便回复邮件啊,所以还是设置设置吧。
下载ZIP文件包含完整的EAR模块和本文所用的代码清单。通过这些现成的解决方案,您可以简单地创建数据库表和服务器项目,然后轻松地运行、调试和测试应用程序。
数据库优化:通过优化数据库结构和查询语句,提高数据库查询效率。异步加载:使用异步加载技术,在用户第一次访问首页时,加载一部分数据,并在后台异步加载剩余数据。
如果要实现懒加载,可以加上注解@Lazy,这个时候,便会在使用到Bean获取该Bean的时候,才会初始化这个Bean。还有一个全局懒加载,则是在启动引导类上面添加上注解@Lazy。这样。所有配置在启动引导类中的@Bean。都会被懒加载。
对于这种加载自定义配置文件的需求,可以使用@PropertySource注解结合@Configuration注解配置类的方式来实现。@PropertySource注解用于指定自定义配置文件的具体位置和名称。
首先在pom.xml中修改SpringBoot的版本号,注意从x版本开始,SpringBoot就不再使用.RELEASE后缀了。
ConfigurationProperties:将全局配置文件的属性值,映射到SpringBoot组件上@Value:从全局配置文件中读取属性,映射到组件上PropertySource:加载指定的配置文件。
SpringBoot使用一个全局的配置文件application.propertiesapplication.yml配置文件的作用:修改SpringBoot自动配置的默认值,SpringBoot在底层都给我们自动配置好。
比如SpringBoot的启动类指定的包扫描路径为com.example数据库的配置文件在com包下。在MyBatisConfig中引入DataSourceConfig,就会解析DataSourceConfig。
1、尽量重用目标特别是,使用代表字符串收敛的String目标应该使用StringBuilder/StringBuffer。
2、使用正确的数据结构和算法:使用正确的数据结构和算法可以极大地提高代码的性能。尽量减少不必要的循环:尽量减少不必要的循环,可以极大地减少代码的执行时间。
3、优化通常包含两方面的内容:减小代码的体积,提高代码的运行效率。本文讨论的主要是如何提高代码的效率。在Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身。
4、)尽量指定类、方法的final修饰符。带有final修饰符的类是不可派生的,Java编译器会寻找机会内联所有的final方法,内联对于提升Java运行效率作用重大,此举能够使性能平均提高50%。2)尽量重用对象。
二、java中的单例模式的代码怎么写
我从我的博客里把我的文章粘贴过来吧,对于单例模式模式应该有比较清楚的解释:
单例模式在我们日常的项目中十分常见,当我们在项目中需要一个这样的一个对象,这个对象在内存中只能有一个实例,这时我们就需要用到单例。
一般说来,单例模式通常有以下几种:
private static Singleton instance= new Singleton();
public static Singleton getInstance(){
这是最简单的单例,这种单例最常见,也很可靠!它有个唯一的缺点就是无法完成延迟加载——即当系统还没有用到此单例时,单例就会被加载到内存中。
在这里我们可以做个这样的测试:
System.out.println("createSingleton");
private static Singleton instance= new Singleton();
public static Singleton getInstance(){
public static void testSingleton(){
System.out.println("CreateString");
而我们在另外一个测试类中对它进行测试(本例所有测试都通过Junit进行测试)
我们可以注意到,在这个单例中,即使我们没有使用单例类,它还是被创建出来了,这当然是我们所不愿意看到的,所以也就有了以下一种单例。
System.out.println("createSingleton");
private static Singleton1 instance= null;
public static synchronized Singleton1 getInstance(){
return instance==null?new Singleton1():instance;
public static void testSingleton(){
System.out.println("CreateString");
上面的单例获取实例时,是需要加上同步的,如果不加上同步,在多线程的环境中,当线程1完成新建单例操作,而在完成赋值操作之前,线程2就可能判
断instance为空,此时,线程2也将启动新建单例的操作,那么多个就出现了多个实例被新建,也就违反了我们使用单例模式的初衷了。
我们在这里也通过一个测试类,对它进行测试,最后面输出是
可以看出,在未使用到单例类时,单例类并不会加载到内存中,只有我们需要使用到他的时候,才会进行实例化。
这种单例解决了单例的延迟加载,但是由于引入了同步的关键字,因此在多线程的环境下,所需的消耗的时间要远远大于第一种单例。我们可以通过一段测试代码来说明这个问题。
long beginTime1= System.currentTimeMillis();
for(int i=0;i<100000;i++){
System.out.println("单例1花费时间:"+(System.currentTimeMillis()-beginTime1));
long beginTime2= System.currentTimeMillis();
for(int i=0;i<100000;i++){
System.out.println("单例2花费时间:"+(System.currentTimeMillis()-beginTime2));
可以看到,使用第一种单例耗时0ms,第二种单例耗时10ms,性能上存在明显的差异。为了使用延迟加载的功能,而导致单例的性能上存在明显差异,
是不是会得不偿失呢?是否可以找到一种更好的解决的办法呢?既可以解决延迟加载,又不至于性能损耗过多,所以,也就有了第三种单例:
private static class SingletonHolder{
private static Singleton2 instance=new Singleton2();
private static Singleton2 getInstance(){
return SingletonHolder.instance;
在这个单例中,我们通过静态内部类来托管单例,当这个单例被加载时,不会初始化单例类,只有当getInstance方法被调用的时候,才会去加载
SingletonHolder,从而才会去初始化instance。并且,单例的加载是在内部类的加载的时候完成的,所以天生对线程友好,而且也不需要
synchnoized关键字,可以说是兼具了以上的两个优点。
一般来说,上述的单例已经基本可以保证在一个系统中只会存在一个实例了,但是,仍然可能会有其他的情况,导致系统生成多个单例,请看以下情况:
public class Singleton3 implements Serializable{
private static class SingletonHolder{
private static Singleton3 instance= new Singleton3();
public static Singleton3 getInstance(){
return SingletonHolder.instance;
public void test() throws Exception{
Singleton3 s2= Singleton3.getInstance();
FileOutputStream fos= new FileOutputStream("singleton.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
FileInputStream fis= new FileInputStream("singleton.txt");
ObjectInputStream ois= new ObjectInputStream(fis);
s1=(Singleton3) ois.readObject();
System.out.println("同一个实例");
System.out.println("不是同一个实例");
可以看到当我们把单例反序列化后,生成了多个不同的单例类,此时,我们必须在原来的代码中加入readResolve()函数,来阻止它生成新的单例
public class Singleton3 implements Serializable{
private static class SingletonHolder{
private static Singleton3 instance= new Singleton3();
public static Singleton3 getInstance(){
return SingletonHolder.instance;
return SingletonHolder.instance;
再次测试时,就可以发现他们生成的是同一个实例了。
三、JPA2.0对于javaEE的进步在哪儿
JavaEE 5平台引入了Java持久化API(Java Persistence API,JPA),它为Java EE和Java SE应用程序提供了一个基于POJO的持久化模块。JPA处理关系数据与Java对象之间的映射,它使对象/关系(O/R)映射标准化,JPA已经被广泛采用,已经成为事实上的O/R持久化企业标准。
Java EE 6带来了JPA的最新版本— JSR 317:Java持久化2.0,JPA 2.0带来了许多新特性和增强,包括:
JPA 1.0支持集合的映射,但这些集合只能包含实体,JPA 2.0增加了集合映射的基础数据类型,如String和Integer,以及嵌入式对象的集合。JPA中的嵌入式对象是一个不能存在于它自身的对象,而是作为父对象的一部分存在,即它的数据不是存在于它自己的表中,而是嵌入在父对象的表中。
JPA 2.0增加了两个支持新的集合映射的注解:@ElementCollection和@CollectionTable。使用@ElementCollection注解指定集合的嵌入式对象,这些集合是独立存储 href=”” target=_blank>存储在集合表中的,使用@CollectionTable注解指定集合表的详细信息,如它包含的列。
下面是一个嵌入式类,表示了车辆的访问服务,它存储了访问的日期,描述和费用,此外,车辆可以配备一或多个可选功能,每个功能是FeatureType类型的一个枚举值。
publicenumFeatureType{ AC, CRUISE, PWR, BLUETOOTH, TV,…}
枚举值和嵌入式对象可以在一个表示车辆服务历史的实体中使用,如:
.@Column(name=”FEAT”) Set<FeatureType> optionalFeatures;
@CollectionTable(name=”VEH_SVC”)
Vehicle实体中的第一对注解@ElementCollection和@CollectionTable指定FeatureType值存储在VEH_OPTNS集合表中,第二对注解@ElementCollection和@CollectionTable指定ServiceVisit嵌入式对象存储在VEH_SVC集合表中。
虽然在例子中没有显示,@ElementCollection注解有两个属性:targetClass和 fetch。targetClass属性指定基础类或嵌入式类的类名,如果字段或属性是使用泛型定义的,那这两个属性是可选的,上面这个例子就是这样。Fetch属性是可选的,它指定集合是延后检索还是立即检索,使用javax.persistence.FetchType常量,值分别用LAZY和EAGER,默认情况下,集合是延后匹配的。
JPA 2.0中还有其它许多关于对象/关系映射的增强,例如,JPA 2.0支持嵌套式嵌入,关系嵌入和有序列表,也增加了新的注解增强映射功能,通过@Access注解更灵活地支持特定的访问类型,更多用于实体关系的映射选项,如对单向一对多关系的外键映射支持,通过@MapsId注解支持派生身份,支持孤体删除。
JPA 1.0定义了一个广泛的Java持久化查询语言,使用它你可以查询实体和它们的持久化状态。JPA 2.0对JPQL做了大量改进,如现在可以在查询中使用case表达式。在下面的查询中,如果雇员的评分为1,则通过乘以1.1对雇员的薪水进行了增长,如果评分为2,则乘以1.05,其它评分则乘以1.01。
CASEWHENe.rating=1THENe.salary*
JPA 2.0也为JPQL增加了大量新的运算符,如NULLIF和COALESCE,当数据库使用其它非空数据解码时,NULLIF运算符是非常有用的,使用NULLIF,你可以在查询中将这些值转换为空值,如果参数等于NULLIF,NULLIF会返回空值,否则返回第一个参数的值。
假设薪水数据保存在employee表中,数据类型为整数,却掉的薪水解码为-9999,下面的查询返回薪水的平均值,为了正确地忽略却掉的薪水,查询使用NULLIF将-9999转换为空值。
COALESCE运算符接收一串参数,从列表中返回第一个非空值,相当于下面的case表达式:
COALESCE运算符接收一串参数,从列表中返回第一个非空值,相当于下面的case表达式:
(e.work_phone, e.home_phone) phone
假设employee表包括一个办公电话号码和家庭电话号码列,无电话号码的列使用空值表示。下面的查询返回每个雇员的姓名和电话号码,COALESCE运算符指定查询返回办公电话号码,但如果为空,则返回家庭电话号码,如果两者都为空,则返回一个空值。
JPA 2.0向JPQL增加的其它运算符是INDEX,TYPE,KEY,VALUE和ENTRY。INDEX运算符指定查询时的排序顺序,TYPE运算符选择一个实体的类型,将查询限制到一或多个实体类型,KEY,VALUE和ENTRY运算符是JPA 2.0中的泛化映射功能的一部分。使用KEY运算符提取映射键,VALUE运算符提取映射值,ENTRY运算符选择一个映射实体。
此外,JPA 2.0增加了选择列表、以及集合值参数和非多态查询中运算符的支持。
JPA 2.0中引入的另一个重要特性是标准的API,利用这个API可以动态地构建基于对象的查询,本质上,这个标准API等价于面向对象的JPQL,使用它,你可以使用基于对象的方法创建查询,不再需要JPQL使用的字符串操作。
标准API是基于元模型的,元模型是一个提供了架构级关于持久化单元托管类的元数据的抽象模型,元模型让你构建强类型的查询,它也允许你浏览持久化单元的逻辑结构。
通常,一个注解处理器使用元模型生成静态元模型类,这些类提供持久化状态和持久化单元托管类的关系,但你可以对静态元模型类编码。下面是一个实体实例:
importjavax.persistence.meta,model.SingularAttribute;
javax.persistence.meta,model.StaticMetamodel;
@Generated(“EclipseLink JPA 2.0 Canonical Model Generation”
SingularAttribute<Employee, Long> id;
SingularAttribute<Employee, String> firstName;
SingularAttribute<Employee, String> lastName;
SingularAttribute<Employee, Department> dept;
此外,JPA 2.0元模型API允许你动态访问元模型,因此当你使用标准API时,既可以静态访问元模型类,也可以动态访问元模型类。标准API提供了更好的灵活性,既可以使用基于对象的方法,又可以使用基于字符串的方法导航元模型,这意味着你有四种使用标准API的方法:
无论你使用哪种方法,通过构造一个CriteriaQuery对象定义一个基于标准API的查询时,使用一个工厂对象CriteriaBuilder构造CriteriaQuery,可以从EntityManager或 EntityManagerFactory类中获得CriteriaBuilder。下面的代码构造一个CriteriaQuery对象:
CriteriaBuilder cb= em.getCriteriaBuilder();
CriteriaQuery<Customer> cq= cb.createQuery(Customer.
注意CriteriaQuery对象是泛型类型,使用CriteriaBuilder的createQuery方法创建一个CriteriaQuery,并为查询结果指定类型。在这个例子中,createQuery方法的Employee.class参数指定查询结果类型是Employee。CriteriaQuery对象和创建它们的方法是强类型的。
接下来,为CriteriaQuery对象指定一个或多个查询源,查询源表示查询基于的实体。你创建一个查询源,然后使用AbstractQuery接口的from()方法将其添加到查询。AbstractQuery接口是众多接口中的一员,如CriteriaQuery,From和root,它们都定义在标准API中。CriteriaQuery接口继承AbstractQuery接口的属性。
from()方法的参数是实体类或EntityType实体的实例,from()方法的结果是一个Root对象,Root接口扩展From接口,它表示某个查询的from子句中可能出现的对象。
下面的代码增加一个查询源到CriteriaQuery对象:
CriteriaBuilder cb= em.getCriteriaBuilder();
CriteriaQuery<Employee> cq= cb.createQuery(Employee.
Root<Employee> emp= cq.from(Employee.
当你向CriteriaQuery对象添加一个或多个查询源后,你访问元模型,然后构造一个查询表达式,你如何做取决于你是以静态方式提交查询还是以动态方式提交查询,以及是使用元模型还是字符串导航元模型。下面是一个使用元模型类静态查询的例子:
cq.where(cb.equal(emp.get(Employee_.lastName),“Smith”));
TypedQuery<Employee> query= em.createQuery(cq);
List<Employee> rows= query.getResultList();
CriteriaQuery接口的select()和 where()方法指定查询结果返回的选择项目。
注意,你使用EntityManager创建查询时,可以在输入中指定一个CriteriaQuery对象,它返回一个TypedQuery,它是JPA 2.0引入javax.persistence.Query接口的一个扩展,TypedQuery接口知道它返回的类型。
在元模型术语中,Employee_是对应于Employee实体类的规范化元模型类,一个规范化元模型类遵循JPA 2.0规范中描述的某些规则。例如,元模型类的名字来源于托管类,一般都是在托管类名字后面追加一个下划线“_”。一个规范化元模型是一个包含静态元模型类的元模型,这个静态元模型对应于实体,映射的超类,以及持久化单元中的嵌入式类。实际上,这个查询使用了规范化元模型。下面是一个完整的查询:
CriteriaBuilder cb= em.getCriteriaBuilder();
CriteriaQuery<Employee> cq= cb.createQuery(Employee.
Root<Employee> emp= cq.from(Employee.
cq.where(cb.equal(emp.get(Employee_.lastName),“Smith”));
TypedQuery<Employee> query= em.createQuery(cq);
List<Employee> rows= query.getResultList();
下面是使用元模型API查询的动态版本:
CriteriaBuilder cb= em.getCriteriaBuilder();
CriteriaQuery<Employee> cq= cb.createQuery(Employee.
Root<Employee> emp= cq.from(Employee.
EntityType<Employee> emp_= emp.getModel();
cq.where(cb.equal(emp.get(emp_.getSingularAttribute(“lastName”, String.
TypedQuery<Employee> query=em.createQuery(cq);
List<Employee> rows=query.getResultList();
使用元模型API的标准查询提供了与使用规范化元模型相同的类型,但它比基于规范化元模型的查询更冗长。
Root的getModel()方法返回根对应的元模型实体,它也允许运行时访问在Employee实体中声明的持久化属性。
getSingularAttribute()方法是一个元模型API方法,它返回一个持久化的单值属性或字段,在这个例子中,它返回值为Smith的lastName属性。下面是使用字符串的元数据导航查询的静态版本:
CriteriaBuilder cb= em.getCriteriaBuilder();
CriteriaQuery<Employee> cq= cb.createQuery(Employee.
Root<Employee> emp= cq.from(Employee.
cq.where(cb.equal(emp.get(“lastName”),“Smith”));
TypedQuery query= em.createQuery(cq);
List<Employee>rows= query.getResultList();
这个基于字符串的方法要相对容易使用些,但却失去了元模型具有的类型安全href=”” target=_blank>安全。
锁是处理数据库事务并发的一种技术,当两个或更多数据库事务并发地访问相同数据时,锁可以保证同一时间只有一个事务可以修改数据。
锁的方法通常有两种:乐观锁和悲观锁。乐观锁认为多个并发事务之间很少出现冲突,也就是说不会经常出现同一时间读取或修改相同数据,在乐观锁中,其目标是让并发事务自由地同时得到处理,而不是发现或预防冲突。两个事务在同一时刻可以访问相同的数据,但为了预防冲突,需要对数据执行一次检查,检查自上次读取数据以来发生的任何变化。
悲观锁认为事务会经常发生冲突,在悲观锁中,读取数据的事务会锁定数据,在前面的事务提交之前,其它事务都不能修改数据。
JPA 1.0只支持乐观锁,你可以使用EntityManager类的lock()方法指定锁模式的值,可以是READ或WRITE,如:
EntityManager em=…;em.lock(p1, READ);
对于READ锁模式,JPA实体管理器在事务提交前都会锁定实体,检查实体的版本属性确定实体自上次被读取以来是否有更新,如果版本属性被更新了,实体管理器会抛出一个OptimisticLockException异常,并回滚事务。
对于WRITE锁模式,实体管理器执行和READ锁模式相同的乐观锁操作,但它也会更新实体的版本列。
JPA 2.0增加了6种新的锁模式,其中两个是乐观锁。JPA 2.0也允许悲观锁,并增加了3种悲观锁,第6种锁模式是无锁。
1、OPTIMISTIC:它和READ锁模式相同,JPA 2.0仍然支持READ锁模式,但明确指出在新应用程序中推荐使用OPTIMISTIC。
2、OPTIMISTIC_FORCE_INCREMENT:它和WRITE锁模式相同,JPA 2.0仍然支持WRITE锁模式,但明确指出在新应用程序中推荐使用OPTIMISTIC_FORCE_INCREMENT。
1、PESSIMISTIC_READ:只要事务读实体,实体管理器就锁定实体,直到事务完成锁才会解开,当你想使用重复读语义查询数据时使用这种锁模式,换句话说就是,当你想确保数据在连续读期间不被修改,这种锁模式不会阻碍其它事务读取数据。
2、PESSIMISTIC_WRITE:只要事务更新实体,实体管理器就会锁定实体,这种锁模式强制尝试修改实体数据的事务串行化,当多个并发更新事务出现更新失败几率较高时使用这种锁模式。
3、PESSIMISTIC_FORCE_INCREMENT:当事务读实体时,实体管理器就锁定实体,当事务结束时会增加实体的版本属性,即使实体没有修改。
你也可以指定新的锁模式NONE,在这种情况下表示没有锁发生。
JPA 2.0也提供了多种方法为实体指定锁模式,你可以使用EntityManager的lock()和 find()方法指定锁模式。此外,EntityManager.refresh()方法可以恢复实体实例的状态。
下面的代码显示了使用PESSIMISTIC_WRITE锁模式的悲观锁:
// lock and refresh before update
em.refresh(p, PESSIMISTIC_WRITE);
在这个例子中,它首先读取一些数据,然后应用PESSIMISTIC_WRITE锁,在更新数据之前调用EntityManager.refresh()方法,当事务更新实体时,PESSIMISTIC_WRITE锁锁定实体,其它事务就不能更新相同的实体,直到前面的事务提交。