Java經(jīng)典面試題最全匯總208道(四)
前言
短時(shí)間提升自己最快的手段就是背面試題,最近總結(jié)了Java常用的面試題,分享給大家,希望大家都能圓夢(mèng)大廠,加油,我命由我不由天。
126、Spring 框架中的單例 Beans 是線程安全的么?
Spring框架并沒(méi)有對(duì)單例bean進(jìn)行任何多線程的封裝處理。
關(guān)于單例bean的線程安全和并發(fā)問(wèn)題需要開(kāi)發(fā)者自行去搞定。
但實(shí)際上,大部分的Spring bean并沒(méi)有可變的狀態(tài),所以在某種程度上說(shuō)Spring的單例bean時(shí)線程安全的。
如果你的bean有多種狀態(tài)的話,比如view model,就需要自行保證線程安全啦。
最淺顯的解決辦法就是將多態(tài)bean的作用域由singleton變更為prototype。
127、請(qǐng)解釋 Spring Bean 的自動(dòng)裝配?
Spring支持IOC,自動(dòng)裝配不用類實(shí)例化,直接從bean容器中取。
1、配置在xml中
<bean id="employeeDAO" class="com.guor.EmployeeDAOImpl" autowire="byName" />
2、@Autowired自動(dòng)裝配
128、如何開(kāi)啟基于注解的自動(dòng)裝配?
要使用 @Autowired,需要注冊(cè) AutowiredAnnotationBeanPostProcessor,可以有以下兩種方式來(lái)實(shí)現(xiàn):
引入配置文件中的<bean>下引入 <context:annotation-config>
<beans>
<context:annotation-config />
</beans>在bean配置文件中直接引入AutowiredAnnotationBeanPostProcessor
<beans>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
</beans>129、什么是 Spring Batch?
1、什么是spring batch?
spring batch是一個(gè)輕量級(jí)的、完善的批處理框架,它主要的目的在于幫助企業(yè)建立健壯、高效的批處理應(yīng)用。
spring batch是Spring的一個(gè)子項(xiàng)目,它使用java語(yǔ)言并基于spring框架作為基礎(chǔ)開(kāi)發(fā),使得已經(jīng)使用Spring框架的開(kāi)發(fā)者或者是企業(yè)可以更加容易訪問(wèn)和利用企業(yè)服務(wù)。
spring batch提供了大量可重用的組件,包括了日志、追蹤、事務(wù)、任務(wù)作業(yè)統(tǒng)計(jì)、任務(wù)重啟、跳過(guò)、重復(fù)、資源管理。
對(duì)大數(shù)據(jù)量和高性能的批處理任務(wù),spring batch同樣提供了高級(jí)功能和特性來(lái)支持。
例如:分區(qū)功能、遠(yuǎn)程功能。
總的來(lái)說(shuō),spring batch可以支持簡(jiǎn)單的、復(fù)雜的和大數(shù)據(jù)量的批處理作業(yè)。
2、spring batch業(yè)務(wù)場(chǎng)景
周期性的提交批處理
把一個(gè)任務(wù)并行處理
消息驅(qū)動(dòng)應(yīng)用分級(jí)處理
大規(guī)模并行批處理
手工或調(diào)度使任務(wù)失敗之后重新啟動(dòng)
有依賴步驟的順序執(zhí)行(使用工作流驅(qū)動(dòng)擴(kuò)展)
處理時(shí)跳過(guò)部分記錄
成批事務(wù):為小批量的或有的存儲(chǔ)過(guò)程/腳本的場(chǎng)景使用
130、spring mvc 和 struts 的區(qū)別是什么?
1、攔截機(jī)制的不同
Struts2是類級(jí)別的攔截,每次請(qǐng)求就會(huì)創(chuàng)建一個(gè)Action,和Spring整合時(shí)Struts2的ActionBean注入作用域是原型模式prototype,然后通過(guò)setter,getter吧request數(shù)據(jù)注入到屬性。
Struts2中,一個(gè)Action對(duì)應(yīng)一個(gè)request,response上下文,在接收參數(shù)時(shí),可以通過(guò)屬性接收,這說(shuō)明屬性參數(shù)是讓多個(gè)方法共享的。
Struts2中Action的一個(gè)方法可以對(duì)應(yīng)一個(gè)url,而其類屬性卻被所有方法共享,這也就無(wú)法用注解或其他方式標(biāo)識(shí)其所屬方法了,只能設(shè)計(jì)為多例。
SpringMVC是方法級(jí)別的攔截,一個(gè)方法對(duì)應(yīng)一個(gè)Request上下文,所以方法直接基本上是獨(dú)立的,獨(dú)享request,response數(shù)據(jù)。
而每個(gè)方法同時(shí)又何一個(gè)url對(duì)應(yīng),參數(shù)的傳遞是直接注入到方法中的,是方法所獨(dú)有的。
處理結(jié)果通過(guò)ModeMap返回給框架。在Spring整合時(shí),SpringMVC的Controller Bean默認(rèn)單例模式Singleton,所以默認(rèn)對(duì)所有的請(qǐng)求,只會(huì)創(chuàng)建一個(gè)Controller,有應(yīng)為沒(méi)有共享的屬性,所以是線程安全的,如果要改變默認(rèn)的作用域,需要添加@Scope注解修改。
Struts2有自己的攔截Interceptor機(jī)制,SpringMVC這是用的是獨(dú)立的Aop方式,這樣導(dǎo)致Struts2的配置文件量還是比SpringMVC大。
2、底層框架的不同
Struts2采用Filter(StrutsPrepareAndExecuteFilter)實(shí)現(xiàn),SpringMVC(DispatcherServlet)則采用Servlet實(shí)現(xiàn)。Filter在容器啟動(dòng)之后即初始化;服務(wù)停止以后墜毀,晚于Servlet。Servlet在是在調(diào)用時(shí)初始化,先于Filter調(diào)用,服務(wù)停止后銷毀。
3、性能方面
Struts2是類級(jí)別的攔截,每次請(qǐng)求對(duì)應(yīng)實(shí)例一個(gè)新的Action,需要加載所有的屬性值注入,SpringMVC實(shí)現(xiàn)了零配置,由于SpringMVC基于方法的攔截,有加載一次單例模式bean注入。
所以,SpringMVC開(kāi)發(fā)效率和性能高于Struts2。
4、配置方面
spring MVC和Spring是無(wú)縫的。從這個(gè)項(xiàng)目的管理和安全上也比Struts2高。
131、請(qǐng)舉例解釋@Required 注解?
@Required注解應(yīng)用于bean屬性的setter方法,它表明影響的bean屬性在配置時(shí)必須放在XML配置文件中。
請(qǐng)舉例說(shuō)明@Qualifier 注解?
如果在xml中定義了一種類型的多個(gè)bean,同時(shí)在java注解中又想把其中一個(gè)bean對(duì)象作為屬性,那么此時(shí)可以使用@Qualifier加@Autowired來(lái)達(dá)到這一目的
若不加@Qualifier這個(gè)注解,在運(yùn)行時(shí)會(huì)出現(xiàn)“ No qualifying bean of type [com.tutorialspoint.Student] is defined: expected single matching bean but found 2: student1,student2”這個(gè)異常。
132、Spring常用注解
Spring常用注解(絕對(duì)經(jīng)典)
133、項(xiàng)目中是如何實(shí)現(xiàn)權(quán)限驗(yàn)證的,權(quán)限驗(yàn)證需要幾張表
通過(guò)了解,現(xiàn)在最普遍的權(quán)限管理模型就是RBAC(Role-Based Access Control)。
1、權(quán)限控制分類
菜單功能
url控制(控制訪問(wèn)不同的控制器)
2、RBAC的優(yōu)缺點(diǎn)
(1)優(yōu)點(diǎn)
簡(jiǎn)化了用戶和權(quán)限的關(guān)系
易擴(kuò)展、易維護(hù)
(2)缺點(diǎn)
RBAC模型沒(méi)有提供操作順序的控制機(jī)制,這一缺陷使得RBAC模型很難適應(yīng)哪些對(duì)操作次序有嚴(yán)格要求的系統(tǒng)。
3、RBAC支持的安全原則
(1)最小權(quán)限原則
RBAC可以將角色配置成其完成任務(wù)所需的最小權(quán)限集合。
(2)責(zé)任分離原則
可以通過(guò)調(diào)用相互獨(dú)立互斥的角色來(lái)共同完成敏感的任務(wù),例如要求一個(gè)記賬員和財(cái)務(wù)管理員共同參與統(tǒng)一過(guò)賬操作。
(3)數(shù)據(jù)抽象原則
可以通過(guò)權(quán)限的抽象來(lái)體現(xiàn),例如財(cái)務(wù)操作用借款、存款等抽象權(quán)限,而不是使用典型的讀寫權(quán)限。
4、遠(yuǎn)古時(shí)代的權(quán)限控制
當(dāng)時(shí)還沒(méi)有RBAC,也沒(méi)有這個(gè)概念,就是一堆程序員在那鼓搗,覺(jué)得登錄這塊該做點(diǎn)什么。

1、新建一個(gè)用戶,對(duì)這個(gè)用戶進(jìn)行賦予權(quán)限。
2、但是一旦用戶多了,權(quán)限復(fù)雜了,這工作量也是蠻大的。
5、RBAC
RBAC 1.0


直接上圖,一目了然,當(dāng)程序不是很復(fù)雜的時(shí)候,RBAC就是這樣設(shè)計(jì)的,我們公司的權(quán)限驗(yàn)證模塊就是這樣設(shè)計(jì)的。
簡(jiǎn)簡(jiǎn)單單,五張表,解
RBAC 2.0
基于RBAC 1.0模型的基礎(chǔ)上,進(jìn)行了角色的訪問(wèn)控制

RBAC2中的一個(gè)基本限制是互斥角色的限制,互斥角色是指各自權(quán)限可以互相制約的兩個(gè)角色。
對(duì)于這類角色一個(gè)用戶在某一次活動(dòng)中只能被分配其中的一個(gè)角色,不能同時(shí)獲得兩個(gè)角色的使用權(quán)。
該模型有以下幾種約束
- 互斥角色 :同一用戶只能分配到一組互斥角色集合中至多一個(gè)角色,支持責(zé)任分離的原則。
互斥角色是指各自權(quán)限互相制約的兩個(gè)角色。
對(duì)于這類角色一個(gè)用戶在某一次活動(dòng)中只能被分配其中的一個(gè)角色,不能同時(shí)獲得兩個(gè)角色的使用權(quán)。
常舉的例子:在審計(jì)活動(dòng)中,一個(gè)角色不能同時(shí)被指派給會(huì)計(jì)角色和審計(jì)員角色。
- 基數(shù)約束 :一個(gè)角色被分配的用戶數(shù)量受限;一個(gè)用戶可擁有的角色數(shù)目受限;同樣一個(gè)角色對(duì)應(yīng)的訪問(wèn)權(quán)限數(shù)目也應(yīng)受限,以控制高級(jí)權(quán)限在系統(tǒng)中的分配。
- 先決條件角色 :可以分配角色給用戶僅當(dāng)該用戶已經(jīng)是另一角色的成員;對(duì)應(yīng)的可以分配訪問(wèn)權(quán)限給角色,僅當(dāng)該角色已經(jīng)擁有另一種訪問(wèn)權(quán)限。
指要想獲得較高的權(quán)限,要首先擁有低一級(jí)的權(quán)限。
- 運(yùn)行時(shí)互斥 :例如,允許一個(gè)用戶具有兩個(gè)角色的成員資格,但在運(yùn)行中不可同時(shí)激活這兩個(gè)角色。
6、rbac的實(shí)現(xiàn)理論分析
進(jìn)入登錄頁(yè)面;
拿到通過(guò)post傳過(guò)來(lái)的用戶名和密碼;
使用orm進(jìn)行過(guò)濾查找;
如果能找到值,則說(shuō)明登錄成功:登錄成功后調(diào)用rbac初始化函數(shù),初始化函數(shù)的主要功能是獲取用戶的權(quán)限和菜單保存到session中,并跳轉(zhuǎn)客戶列表頁(yè)面;
如果失敗,頁(yè)面進(jìn)行友好提示;
7、url權(quán)限控制關(guān)鍵代碼

134、談?wù)刢ontroller,接口調(diào)用的路徑問(wèn)題
1、Spring MVC如何匹配請(qǐng)求路徑
@RequestMapping是用來(lái)映射請(qǐng)求的,比如get請(qǐng)求、post請(qǐng)求、或者REST風(fēng)格與非REST風(fēng)格的。
該注解可以用在類上或方法上,如果用在類上,表示是該類中所有方法的父路徑。
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
@RequestMapping("/testRequestMapping")
public String testRequestMapping(){
System.out.println("testRequestMapping");
return SUCCESS;
}
}在類上還添加了一個(gè)@Controller注解,該注解在SpringMVC中負(fù)責(zé)處理由DispatcherServlet分發(fā)的請(qǐng)求,它把用戶請(qǐng)求的數(shù)據(jù)經(jīng)過(guò)業(yè)務(wù)處理層處理之后封裝成一個(gè)model,然后再把該model返回給對(duì)應(yīng)的view進(jìn)行展示。
我們可以通過(guò)“springmvc/testRequestMapping”這個(gè)路徑來(lái)定位到testRequestMapping這個(gè)方法,然后執(zhí)行方法內(nèi)的方法體。
RequestMapping可以實(shí)現(xiàn)模糊匹配路徑,比如:
- ?表示一個(gè)字符;
- *表示任意字符;
- **匹配多層路徑;
/springmvc/**/testRequestMapping 就可以匹配/springmvc/stu/getStudentInfo/testRequestMapping 這樣的路徑了。
2、SpringMVC如何獲取請(qǐng)求的參數(shù)
(1)@PathVariable
該注解用來(lái)映射請(qǐng)求URL中綁定的占位符。通過(guò)@PathVariable可以將URL中占位符的參數(shù)綁定到controller處理方法的入?yún)⒅小?/p>
@RequestMapping("/testPathVariable/{id}")
public String testPathVariable(@PathVariable(value="id") Integer id){
System.out.println("testPathVariable:" + id);
return SUCCESS;
}在index.jsp中我們添加一條連接,用來(lái)觸發(fā)一個(gè)請(qǐng)求:
<a href="springmvc/testPathVariable/1" rel="external nofollow" >testPathVariable</a>
(2) @RequestParam
該注解也是用來(lái)獲取請(qǐng)求參數(shù)的,那么該注解和@PathVariable有什么不同呢?
@RequestMapping(value="/testRequestParam")
public String testRequestParam(@RequestParam(value="username") String username, @RequestParam(value="age", required=false, defaultValue="0") int age){
System.out.println("testRequestParam" + " username:" + username + " age:" +age);
return SUCCESS;
}在index.jsp添加超鏈接標(biāo)簽
<a href="springmvc/testRequestParam?username=jackie&age=12" rel="external nofollow" >testRequestParam</a>
3、REST風(fēng)格的請(qǐng)求
在SpringMVC中業(yè)務(wù)最多的應(yīng)該是CRUD了
@RequestMapping(value="/testRest/{id}", method=RequestMethod.PUT)
public String testRestPut(@PathVariable(value="id") Integer id){
System.out.println("test put:" + id);
return SUCCESS;
}
@RequestMapping(value="/testRest/{id}", method=RequestMethod.DELETE)
public String testRestDelete(@PathVariable(value="id") Integer id){
System.out.println("test delete:" + id);
return SUCCESS;
}
@RequestMapping(value="/testRest", method=RequestMethod.POST)
public String testRest(){
System.out.println("test post");
return SUCCESS;
}
@RequestMapping(value="/testRest/{id}", method=RequestMethod.GET)
public String testRest(@PathVariable(value="id") Integer id){
System.out.println("test get:" + id);
return SUCCESS;
}135、如何防止表單重復(fù)提交
1、通過(guò)JavaScript屏蔽提交按鈕(不推薦)
2、給數(shù)據(jù)庫(kù)增加唯一鍵約束(簡(jiǎn)單粗暴)
3、利用Session防止表單重復(fù)提交(推薦)
4、使用AOP自定義切入實(shí)現(xiàn)
136、Spring中都應(yīng)用了哪些設(shè)計(jì)模式
1、簡(jiǎn)單工廠模式
簡(jiǎn)單工廠模式的本質(zhì)就是一個(gè)工廠類根據(jù)傳入的參數(shù),動(dòng)態(tài)的決定實(shí)例化哪個(gè)類。
Spring中的BeanFactory就是簡(jiǎn)單工廠模式的體現(xiàn),根據(jù)傳入一個(gè)唯一的標(biāo)識(shí)來(lái)獲得bean對(duì)象。
2、工廠方法模式
應(yīng)用程序?qū)?duì)象的創(chuàng)建及初始化職責(zé)交給工廠對(duì)象,工廠Bean。
定義工廠方法,然后通過(guò)config.xml配置文件,將其納入Spring容器來(lái)管理,需要通過(guò)factory-method指定靜態(tài)方法名稱。
3、單例模式
Spring用的是雙重判斷加鎖的單例模式,通過(guò)getSingleton方法從singletonObjects中獲取bean。
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}4、代理模式
Spring的AOP中,使用的Advice(通知)來(lái)增強(qiáng)被代理類的功能。
Spring實(shí)現(xiàn)AOP功能的原理就是代理模式(① JDK動(dòng)態(tài)代理,② CGLIB字節(jié)碼生成技術(shù)代理。)對(duì)類進(jìn)行方法級(jí)別的切面增強(qiáng)。
5、裝飾器模式
裝飾器模式:動(dòng)態(tài)的給一個(gè)對(duì)象添加一些額外的功能。
Spring的ApplicationContext中配置所有的DataSource。
這些DataSource可能是不同的數(shù)據(jù)庫(kù),然后SessionFactory根據(jù)用戶的每次請(qǐng)求,將DataSource設(shè)置成不同的數(shù)據(jù)源,以達(dá)到切換數(shù)據(jù)源的目的。
在Spring中有兩種表現(xiàn):
一種是類名中含有Wrapper,另一種是類名中含有Decorator。
6、觀察者模式
定義對(duì)象間的一對(duì)多的關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并自動(dòng)更新。
Spring中觀察者模式一般用在listener的實(shí)現(xiàn)。
7、策略模式
策略模式是行為性模式,調(diào)用不同的方法,適應(yīng)行為的變化 ,強(qiáng)調(diào)父類的調(diào)用子類的特性 。
getHandler是HandlerMapping接口中的唯一方法,用于根據(jù)請(qǐng)求找到匹配的處理器。
8、模板方法模式
Spring JdbcTemplate的query方法總體結(jié)構(gòu)是一個(gè)模板方法+回調(diào)函數(shù),query方法中調(diào)用的execute()是一個(gè)模板方法,而預(yù)期的回調(diào)doInStatement(Statement state)方法也是一個(gè)模板方法。
137、請(qǐng)舉例說(shuō)明如何在 Spring 中注入一個(gè) Java Collection?
Spring注入有四種方式,
- set注入;
- 構(gòu)造器注入;
- 基于注解的注入;
- xml配置文件注入;
想要注入java collection,就是注入集合類:
- listsetmapprops:該標(biāo)簽支持注入鍵和值都是字符串類型的鍵值對(duì)。
- list和set都使用value標(biāo)簽;
- map使用entry標(biāo)簽;
- props使用prop標(biāo)簽;
138、mybatis 中 #{}和 ${}的區(qū)別是什么?
- #{}帶引號(hào),${}不帶引號(hào);
- #{}可以防止SQL注入;
- ${}常用于數(shù)據(jù)庫(kù)表名、order by子句;
- 一般能用#{}就不要使用${};
139、mybatis 是否支持延遲加載?延遲加載的原理是什么?
1、mybatis 是否支持延遲加載?
延遲加載其實(shí)就是講數(shù)據(jù)加載時(shí)機(jī)推遲,比如推遲嵌套查詢的時(shí)機(jī)。
延遲加載可以實(shí)現(xiàn)先查詢主表,按需實(shí)時(shí)做關(guān)聯(lián)查詢,返回關(guān)聯(lián)表結(jié)果集,一定程度上提高了效率。
mybatis僅支持關(guān)聯(lián)對(duì)象association和關(guān)聯(lián)集合對(duì)象collection的延遲加載,association是一對(duì)一,collection是一對(duì)多查詢,在mybatis配置文件中可以配置lazyloadingEnable=true/false。
2、延遲加載的原理是什么?
使用CGLIB為目標(biāo)對(duì)象建立代理對(duì)象,當(dāng)調(diào)用目標(biāo)對(duì)象的方法時(shí)進(jìn)入攔截器方法。
比如調(diào)用a.getB().getName(),攔截器方法invoke()發(fā)現(xiàn)a.getB()為null,會(huì)單獨(dú)發(fā)送事先準(zhǔn)備好的查詢關(guān)聯(lián)B對(duì)象的sql語(yǔ)句,把B查詢出來(lái)然后調(diào)用a.setB(b),也是a的對(duì)象的屬性b就有值了,然后調(diào)用getName(),這就是延遲加載的原理。
140、說(shuō)一下 mybatis 的一級(jí)緩存和二級(jí)緩存?
一級(jí)緩存是session級(jí)別的緩存,默認(rèn)開(kāi)啟,當(dāng)查詢一次數(shù)據(jù)庫(kù)時(shí),對(duì)查詢結(jié)果進(jìn)行緩存,如果之后的查詢?cè)谝患?jí)緩存中存在,則無(wú)需再訪問(wèn)數(shù)據(jù)庫(kù);
二級(jí)緩存是sessionFactory級(jí)別的緩存,需要配置才會(huì)開(kāi)啟。當(dāng)進(jìn)行sql語(yǔ)句查詢時(shí),先查看一級(jí)緩存,如果不存在,訪問(wèn)二級(jí)緩存,降低數(shù)據(jù)庫(kù)訪問(wèn)壓力。
141、mybatis 有哪些執(zhí)行器(Executor)?
1、mybatis有三種基本的Executor執(zhí)行器:
(1)、SimpleExecutor
每執(zhí)行一次update或select,就開(kāi)啟一個(gè)Statement對(duì)象,用完立刻關(guān)閉Statement對(duì)象。
(2)、PauseExecutor
執(zhí)行update或select,以sql做為key查找Statement對(duì)象,存在就使用,不存在就創(chuàng)建,用完后,不關(guān)閉Statement對(duì)象,而且放置于Map內(nèi),供下一次使用。
簡(jiǎn)言之,就是重復(fù)使用Statement對(duì)象。
(3)、BatchExecutor
執(zhí)行update,將所有sql通過(guò)addBatch()都添加到批處理中,等待統(tǒng)一執(zhí)行executeBatch(),它緩存了多個(gè)Statement對(duì)象,每個(gè)Statement對(duì)象都是addBatch()完畢后,等待逐一執(zhí)行executeBatch()批處理。
與JDBC批處理相同。
2、作用范圍:
Executor的這些特點(diǎn),都嚴(yán)格限制在SqlSession生命周期范圍內(nèi)。
3、Mybatis中如何指定使用哪一種Executor執(zhí)行器?
在mybatis的配置文件中,可以指定默認(rèn)的ExecutorType執(zhí)行器類型,也可以手動(dòng)給DefaultSqlSessionFactory的創(chuàng)建SqlSession的方法傳遞ExecutorType類型參數(shù)。
142、mybatis 和 hibernate 的區(qū)別有哪些?
1、兩者最大的區(qū)別
針對(duì)簡(jiǎn)單邏輯,都有對(duì)應(yīng)的代碼生成工具,可以生成簡(jiǎn)單基本的dao層方法;
針對(duì)高級(jí)查詢,mybatis要手動(dòng)編寫sql語(yǔ)句和resultMap,而hibernate有良好的映射機(jī)制;
2、開(kāi)發(fā)難度對(duì)比
hibernate > mybatis
3、日志統(tǒng)計(jì)
hibernate有自己的日志統(tǒng)計(jì)功能,而mybatis需要借助log4j來(lái)記錄日志。
4、數(shù)據(jù)庫(kù)擴(kuò)展比較
hibernate > mybatis
5、緩存機(jī)制比較
因?yàn)閔ibernate對(duì)查詢對(duì)象有良好的管理機(jī)制,用戶無(wú)需關(guān)心sql,所以使用二級(jí)緩存如果出現(xiàn)臟數(shù)據(jù),系統(tǒng)會(huì)報(bào)錯(cuò)。
而mybatis,如果不能獲取最新數(shù)據(jù),應(yīng)該避免緩存的使用,臟數(shù)據(jù)的出現(xiàn)會(huì)給系統(tǒng)的正常運(yùn)行帶來(lái)很大的隱患。
6、如何選擇
- mybatis需要編寫sql和映射規(guī)則,工作量大于hibernate;
- mybatis支持的工具也有限,不能像hibernate那樣有許多插件可以幫助生成映射代碼和關(guān)聯(lián)關(guān)系;
- 對(duì)于性能要求不太苛刻的系統(tǒng),比如管理系統(tǒng)、ERP等推薦hibernate;
- 對(duì)于性能要求高、響應(yīng)快、靈活的系統(tǒng),比如電商系統(tǒng),推薦使用mybatis;
143、myBatis查詢多個(gè)id、myBatis常用屬性
myBatis查詢多個(gè)id(我居然回答用對(duì)象來(lái)傳遞...)
Page<UserPoJo> getUserListByIds(@Param("ids") List<Integer> ids);<!--根據(jù)id列表批量查詢user-->
<select id="getUserListByIds" resultType="com.guor.UserPoJo">
select * from student
where id in
<foreach collection="ids" item="userid" open="(" close=")" separator=",">
#{userid}
</foreach>
</select>144、mybatis一級(jí)緩存、二級(jí)緩存
1、一級(jí)緩存:指的是mybatis中sqlSession對(duì)象的緩存,當(dāng)我們執(zhí)行查詢以后,查詢的結(jié)果會(huì)同時(shí)存入sqlSession中,再次查詢的時(shí)候,先去sqlSession中查詢,有的話直接拿出,當(dāng)sqlSession消失時(shí),mybatis的一級(jí)緩存也就消失了,當(dāng)調(diào)用sqlSession的修改、添加、刪除、commit()、close()等方法時(shí),會(huì)清空一級(jí)緩存。
2、二級(jí)緩存:指的是mybatis中的sqlSessionFactory對(duì)象的緩存,由同一個(gè)sqlSessionFactory對(duì)象創(chuàng)建的sqlSession共享其緩存,但是其中緩存的是數(shù)據(jù)而不是對(duì)象。
當(dāng)命中二級(jí)緩存時(shí),通過(guò)存儲(chǔ)的數(shù)據(jù)構(gòu)造成對(duì)象返回。查詢數(shù)據(jù)的時(shí)候,查詢的流程是二級(jí)緩存 > 一級(jí)緩存 > 數(shù)據(jù)庫(kù)。
3、如果開(kāi)啟了二級(jí)緩存,sqlSession進(jìn)行close()后,才會(huì)把sqlSession一級(jí)緩存中的數(shù)據(jù)添加到二級(jí)緩存中,為了將緩存數(shù)據(jù)取出執(zhí)行反序列化,還需要將要緩存的pojo實(shí)現(xiàn)Serializable接口,因?yàn)槎?jí)緩存數(shù)據(jù)存儲(chǔ)介質(zhì)多種多樣,不一定只存在內(nèi)存中,也可能存在硬盤中。
4、mybatis框架主要是圍繞sqlSessionFactory進(jìn)行的,具體的步驟:
定義一個(gè)configuration對(duì)象,其中包含數(shù)據(jù)源、事務(wù)、mapper文件資源以及影響數(shù)據(jù)庫(kù)行為屬性設(shè)置settings。
- 通過(guò)配置對(duì)象,則可以創(chuàng)建一個(gè)sqlSessionFactoryBuilder對(duì)象。
- 通過(guò)sqlSessionFactoryBuilder獲得sqlSessionFactory實(shí)例。
- 通過(guò)sqlSessionFactory實(shí)例創(chuàng)建qlSession實(shí)例,通過(guò)sqlSession對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作。
5、代碼實(shí)例
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加載類路徑下的屬性文件 -->
<properties resource="db.properties"/>
<!-- 設(shè)置類型別名 -->
<typeAliases>
<typeAlias type="cn.itcast.javaee.mybatis.app04.Student" alias="student"/>
</typeAliases>
<!-- 設(shè)置一個(gè)默認(rèn)的連接環(huán)境信息 -->
<environments default="mysql_developer">
<!-- 連接環(huán)境信息,取一個(gè)任意唯一的名字 -->
<environment id="mysql_developer">
<!-- mybatis使用jdbc事務(wù)管理方式 -->
<transactionManager type="jdbc"/>
<!-- mybatis使用連接池方式來(lái)獲取連接 -->
<dataSource type="pooled">
<!-- 配置與數(shù)據(jù)庫(kù)交互的4個(gè)必要屬性 -->
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
<!-- 連接環(huán)境信息,取一個(gè)任意唯一的名字 -->
<environment id="oracle_developer">
<!-- mybatis使用jdbc事務(wù)管理方式 -->
<transactionManager type="jdbc"/>
<!-- mybatis使用連接池方式來(lái)獲取連接 -->
<dataSource type="pooled">
<!-- 配置與數(shù)據(jù)庫(kù)交互的4個(gè)必要屬性 -->
<property name="driver" value="${oracle.driver}"/>
<property name="url" value="${oracle.url}"/>
<property name="username" value="${oracle.username}"/>
<property name="password" value="${oracle.password}"/>
</dataSource>
</environment>
</environments>
<!-- 加載映射文件-->
<mappers>
<mapper resource="cn/itcast/javaee/mybatis/app14/StudentMapper.xml"/>
</mappers>
</configuration> public class MyBatisTest {
public static void main(String[] args) {
try {
//讀取mybatis-config.xml文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//初始化mybatis,創(chuàng)建SqlSessionFactory類的實(shí)例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//創(chuàng)建session實(shí)例
SqlSession session = sqlSessionFactory.openSession();
/*
* 接下來(lái)在這里做很多事情,到目前為止,目的已經(jīng)達(dá)到得到了SqlSession對(duì)象.通過(guò)調(diào)用SqlSession里面的方法,
* 可以測(cè)試MyBatis和Dao層接口方法之間的正確性,當(dāng)然也可以做別的很多事情,在這里就不列舉了
*/
//插入數(shù)據(jù)
User user = new User();
user.setC_password("123");
user.setC_username("123");
user.setC_salt("123");
//第一個(gè)參數(shù)為方法的完全限定名:位置信息+映射文件當(dāng)中的id
session.insert("com.cn.dao.UserMapping.insertUserInformation", user);
//提交事務(wù)
session.commit();
//關(guān)閉session
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}145、mybatis如何防止sql注入
注意:但凡是sql注入漏洞的程序,都是因?yàn)槌绦蛞邮軄?lái)自客戶端用戶輸入的變量或URL傳遞的參數(shù),并且這個(gè)變量或參數(shù)是組成sql語(yǔ)句的一部分,對(duì)于用戶輸入的內(nèi)容或傳遞的參數(shù),我們應(yīng)該要時(shí)刻保持警惕,這是安全領(lǐng)域里的【外部數(shù)據(jù)不可信任】的原則,縱觀web安全領(lǐng)域的各種攻擊方式,大多數(shù)都是因?yàn)殚_(kāi)發(fā)者違反了這個(gè)原則而導(dǎo)致的,所以自然能想到,就是變量的檢測(cè)、過(guò)濾、驗(yàn)證下手,確保變量是開(kāi)發(fā)者所預(yù)想的。
1、檢查變量數(shù)據(jù)類型和格式
數(shù)據(jù)類型檢查,sql執(zhí)行前,要進(jìn)行數(shù)據(jù)類型檢查,如果是郵箱,參數(shù)就必須是郵箱的格式,如果是日期,就必須是日期格式;
只要是有固定格式的變量,在SQL語(yǔ)句執(zhí)行前,應(yīng)該嚴(yán)格按照固定格式去檢查,確保變量是我們預(yù)想的格式,這樣很大程度上可以避免SQL注入攻擊。
如果上述例子中id是int型的,效果會(huì)怎樣呢?無(wú)法注入,因?yàn)檩斎胱⑷雲(yún)?shù)會(huì)失敗。
比如上述中的name字段,我們應(yīng)該在用戶注冊(cè)的時(shí)候,就確定一個(gè)用戶名規(guī)則
比如5-20個(gè)字符,只能由大小寫字母、數(shù)字以及漢字組成,不包含特殊字符。
此時(shí)我們應(yīng)該有一個(gè)函數(shù)來(lái)完成統(tǒng)一的用戶名檢查。
不過(guò),仍然有很多場(chǎng)景并不能用到這個(gè)方法,比如寫博客,評(píng)論系統(tǒng),彈幕系統(tǒng),必須允許用戶可以提交任意形式的字符才行,否則用戶體驗(yàn)感太差了。
2、過(guò)濾特殊符號(hào)
3、綁定變量,使用預(yù)編譯語(yǔ)句
146、為什么要使用 hibernate?
- hibernate對(duì)jdbc進(jìn)行了封裝,簡(jiǎn)化了JDBC的重復(fù)性代碼;
- hibernate對(duì)dao有一個(gè)封裝類hibernateTemplate,可以繼承它,實(shí)現(xiàn)簡(jiǎn)單的CRUD接口。
- hibernate使用注解和配置文件,可以對(duì)實(shí)體類和映射文件進(jìn)行映射;
- hibernate有事務(wù)管理機(jī)制,保證了數(shù)據(jù)的安全性;
- hibernate有一級(jí)緩存和二級(jí)緩存;
146、hibernate 中如何在控制臺(tái)查看打印的 sql 語(yǔ)句?
public class MyBatisTest {
public static void main(String[] args) {
try {
//讀取mybatis-config.xml文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//初始化mybatis,創(chuàng)建SqlSessionFactory類的實(shí)例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//創(chuàng)建session實(shí)例
SqlSession session = sqlSessionFactory.openSession();
/*
* 接下來(lái)在這里做很多事情,到目前為止,目的已經(jīng)達(dá)到得到了SqlSession對(duì)象.通過(guò)調(diào)用SqlSession里面的方法,
* 可以測(cè)試MyBatis和Dao層接口方法之間的正確性,當(dāng)然也可以做別的很多事情,在這里就不列舉了
*/
//插入數(shù)據(jù)
User user = new User();
user.setC_password("123");
user.setC_username("123");
user.setC_salt("123");
//第一個(gè)參數(shù)為方法的完全限定名:位置信息+映射文件當(dāng)中的id
session.insert("com.cn.dao.UserMapping.insertUserInformation", user);
//提交事務(wù)
session.commit();
//關(guān)閉session
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}147、hibernate 有幾種查詢方式?
1、導(dǎo)航對(duì)象圖查詢:根據(jù)已加載的對(duì)象,導(dǎo)航到其他對(duì)象。
例如,對(duì)于已經(jīng)加載的Customer對(duì)象,調(diào)用它的getOrders().iterator()方法就可以導(dǎo)航到所有關(guān)聯(lián)的Order對(duì)象,假如在關(guān)聯(lián)級(jí)別使用了延遲加載檢索策略
那么首次執(zhí)行此方法時(shí),hibernate會(huì)從數(shù)據(jù)庫(kù)中加載關(guān)聯(lián)的Order對(duì)象,否則就從緩存中獲得Order對(duì)象。
2、OID方式:按照對(duì)象的OID來(lái)檢索對(duì)象
Session的get()和load()方法提供了這種功能,如果在應(yīng)用程序中先知道了OID,就可以使用這種方式檢索對(duì)象。
get()和load()的用法完全一樣,都需要兩個(gè)參數(shù),一個(gè)是持久化對(duì)象類名class,一個(gè)是行號(hào)OID,返回固定的某一行的數(shù)據(jù),但是需要注意的是,當(dāng)輸入的OID不存在時(shí),get()會(huì)返回一個(gè)空對(duì)象,load()則直接報(bào)錯(cuò)。
3、HQL檢索方式:(hibernate query language)
使用面向?qū)ο蟮腍QL查詢語(yǔ)言,session的find()方法用于執(zhí)行HQL查詢語(yǔ)句。
此外,hibernate還提供了query接口,它是hibernate提供的專門的HQL查詢接口,能夠執(zhí)行各種復(fù)雜的HQL查詢語(yǔ)句。
它具備以下功能:
- 在查詢語(yǔ)句中設(shè)定各種查詢條件;
- 支持投影查詢,即僅檢索出對(duì)象的部分屬性;
- 支持分頁(yè)查詢;
- 支持連接查詢;
- 支持分組查詢;
- 提供內(nèi)置函數(shù);
- 能夠調(diào)用用戶自定義的SQL函數(shù);
- 支持子查詢;
- 支持動(dòng)態(tài)綁定參數(shù);
例如:
Query query = session.createQuery(“from UserPo”);
獲得一個(gè)query對(duì)象,注意參數(shù)字符串中不是一個(gè)SQL語(yǔ)句,from后面的是持久化對(duì)象名稱;
List list = query.list();
就可以獲取數(shù)據(jù)庫(kù)中對(duì)應(yīng)表的數(shù)據(jù)集合。
4、QBC檢索方式:Query By Criteria的API來(lái)檢索對(duì)象
這種API封裝了基于字符串形式的查詢語(yǔ)句,提供了更加面向?qū)ο蟮慕涌凇?/p>
例:Criteria criteria = session.createCriteria(UserPo.class);
創(chuàng)建一個(gè)Criteria對(duì)象,參數(shù)是所關(guān)聯(lián)的持久化對(duì)象,criteria.add(Restrictions.ge("id",2));將查詢條件加入對(duì)象中,后面的操作就和Query對(duì)象一樣了。
5、本地SQL
使用本地?cái)?shù)據(jù)庫(kù)的SQL查詢語(yǔ)句,hibernate會(huì)負(fù)責(zé)把檢索到的JDBC ResultSet結(jié)果映射為持久化對(duì)象圖。
148、hibernate 實(shí)體類可以被定義為 final 嗎?
可以將hibernate的實(shí)體類定義為final,但這種做法不好。
因?yàn)閔ibernate會(huì)使用代理模式在延遲關(guān)聯(lián)的情況下提高性能,如果你把實(shí)體類定義成final類之后,因?yàn)镴ava不允許對(duì)final類進(jìn)行擴(kuò)展
所以hibernate就無(wú)法再使用代理了,如此一來(lái)就限制了使用可以提升性能的手段。
不過(guò),如果你的持久化類實(shí)現(xiàn)了一個(gè)接口,而且在該接口中聲明了所有定義于實(shí)體類中的所有public的方法的話,就能避免出現(xiàn)前面所說(shuō)的不利后果。
149、在 hibernate 中使用 Integer 和 int 做映射有什么區(qū)別?
hibernate是面向?qū)ο蟮腛RM,所以一般定義成封裝類型,要看數(shù)據(jù)庫(kù)中的定義,如果數(shù)據(jù)庫(kù)中有對(duì)應(yīng)字段存在null值,就要定義Integer。
也可以定義基本類型,在配置文件中寫清楚即可。
150、什么是 Spring Boot?Spring Boot 有哪些優(yōu)點(diǎn)?
1、Spring Boot簡(jiǎn)介
基于Spring4.0設(shè)計(jì),不僅繼承了Spring框架原有的優(yōu)秀特性,而且還通過(guò)簡(jiǎn)化配置來(lái)進(jìn)一步簡(jiǎn)化spring應(yīng)用的整個(gè)搭建和開(kāi)發(fā)過(guò)程。
另外SpringBoot通過(guò)集成大量的框架使得依賴包的版本沖突、引用的不穩(wěn)定性得到了解決。
2、Spring Boot 有哪些優(yōu)點(diǎn)?
- 快速構(gòu)建項(xiàng)目,可以選一些必要的組件;
- 對(duì)主流框架的無(wú)配置集成;
- 內(nèi)嵌Tomcat容器,項(xiàng)目可獨(dú)立運(yùn)行;
- 刪除了繁瑣的xml配置文件;
- 極大地提高了開(kāi)發(fā)和部署效率;
- 提供starter,簡(jiǎn)化maven配置;
3、SpringBoot有哪些缺點(diǎn)?
版本迭代速度快,一些模塊改動(dòng)很大;由于無(wú)須配置,報(bào)錯(cuò)時(shí)很難定位;
151、Spring Boot 中的監(jiān)視器是什么?
監(jiān)聽(tīng)器也叫l(wèi)istener,是servlet的監(jiān)聽(tīng)器,可以用于監(jiān)聽(tīng)web應(yīng)用程序中某些對(duì)象的創(chuàng)建、銷毀、增加、修改、刪除等動(dòng)作的發(fā)生,然后做出相應(yīng)的響應(yīng)處理。
當(dāng)范圍對(duì)象的狀態(tài)發(fā)生變化時(shí),服務(wù)器自動(dòng)調(diào)用監(jiān)聽(tīng)器對(duì)象中的方法,常用于系統(tǒng)加載時(shí)進(jìn)行信息初始化,統(tǒng)計(jì)在線人數(shù)和在線用戶,統(tǒng)計(jì)網(wǎng)站的訪問(wèn)量。
配置監(jiān)聽(tīng)器的方法:
- 通過(guò)@Component把監(jiān)聽(tīng)器加入Spring容器中管理;
- 在application.properties中添加context.listener.classes配置;
- 在方法上加@EventListener注解;
到此這篇關(guān)于Java經(jīng)典面試題最全匯總208道(四)的文章就介紹到這了,更多相關(guān)Java面試題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java GZip 基于內(nèi)存實(shí)現(xiàn)壓縮和解壓的方法
這篇文章主要介紹了Java GZip 基于內(nèi)存實(shí)現(xiàn)壓縮和解壓的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Android內(nèi)存泄漏實(shí)戰(zhàn)解析
Java是垃圾回收語(yǔ)言的一種。這篇文章主要介紹了Android內(nèi)存泄漏 的相關(guān)資料,需要的朋友可以參考下2016-10-10
SpringBoot響應(yīng)Json數(shù)據(jù)亂碼通過(guò)配置的解決
這篇文章主要介紹了SpringBoot響應(yīng)Json數(shù)據(jù)亂碼通過(guò)配置的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
spring boot 1.5.4 集成shiro+cas,實(shí)現(xiàn)單點(diǎn)登錄和權(quán)限控制
這篇文章主要介紹了spring boot 1.5.4 集成shiro+cas,實(shí)現(xiàn)單點(diǎn)登錄和權(quán)限控制,需要的朋友可以參考下2017-06-06
java8學(xué)習(xí)教程之函數(shù)引用的使用方法
這篇文章主要給大家介紹了關(guān)于java8學(xué)習(xí)教程之函數(shù)引用的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)下吧。2017-09-09
詳解Spring Cloud Feign 熔斷配置的一些小坑
這篇文章主要介紹了詳解Spring Cloud Feign 熔斷配置的一些小坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
java 實(shí)現(xiàn)發(fā)短信功能---騰訊云短信
如今發(fā)短信功能已經(jīng)成為互聯(lián)網(wǎng)公司的標(biāo)配,接下來(lái)通過(guò)本文給大家介紹java 實(shí)現(xiàn)發(fā)短信功能---騰訊云短信 ,需要的朋友可以參考下2019-08-08
在SpringBoot中使用@Value注解來(lái)設(shè)置默認(rèn)值的方法
Spring Boot提供了一種使用注解設(shè)置默認(rèn)值的方式,即使用 @Value 注解,下面這篇文章主要給大家介紹了關(guān)于如何在SpringBoot中使用@Value注解來(lái)設(shè)置默認(rèn)值的相關(guān)資料,需要的朋友可以參考下2023-10-10

