Java--Mybatis万字长文经典面试题王者笔记《收藏版》
前言:? ? ? ? ?
? ? ? ?前段時間一直和大家在分享java項目實戰的內容、今天趁著周末給大家整理了Java工程師在面試中經常被問到持久層框架的面試題《Java--Mybatis》篇、希望大家喜歡、支持。后期也會繼續整理其他的知識點、比如、ZooKeeper、Dubbo、Redis、MySQL、Spring、Spring Boot、Spring Cloud、等技術棧。下面就具體看看有哪些經典題目吧、喜歡的可以一鍵三連支持下喲
什么是 Mybatis框架??
? ? ? ?MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射,它內部封裝了jdbc,不需要我們在寫JDBC連接、使開發者只需要關注sql語句本身和業務,而不需要花費精力去處理加載驅動、創建連接、創建statement等繁雜的過程。直接通過配置文件或maven驅動包的方式加載導入就行。
Mybaits 的優點有哪些:? ?? ? ?
Mybatis基于SQL語句編程,很靈活,不會有任何影響現有應用程序或數據庫的設計,SQL編寫的XML,刪除SQL和程序代碼的耦合,便于統一管理,提供了XML標記,使您能夠編寫動態SQL語句和重用它們。
與JDBC相比,它減少了50%以上的代碼量,消除了大量冗余的JDBC代碼,不需要手動切換連接;
與各種數據庫的良好兼容性(因為MyBatis使用JDBC連接數據庫,所以只要JDBC支持數據庫MyBatis就支持)。
與Spring和Spring MVCD框架的良好集成;
提供映射標簽,支持對象與數據庫ORM字段關系映射;提供對象關系映射標簽,支持對象關系組件的維護。
MyBatis 框架的缺點有哪些:? ?
JDBC方式可以用用打斷點的方式調試,但是Mybatis不能,需要通過log4j日志輸出日志信息幫助調試,然后在配置文件中修改。
編寫SQL語句是一項繁重的工作,特別是對于有許多字段和許多關聯表的開發人員來說對于SQL語句的基礎有一定的要求。
SQL語句依賴于數據庫,導致數據庫可移植性差。因此,不能隨意更改數據庫。
MyBatis 框架適用哪些場景:? ?
因為MyBatis 專注于?SQL 本身,是一個足夠靈活的 DAO 層解決方案。滿足基本的單表的CRUD。
對性能的要求比較高,或者需求變化較多的項目,如互聯網重的很多項目基本都是采用的MyBatis 作為持久層框架。
MyBatis 與 Hibernate 的區別?? ?
? ? ? ? MyBatis 支持通過 XML 或注解的方式來配置需要運行的 SQL 語句,并且,最終由框架本身將 Java 對象和 SQL 語句映射生成最終執行的 SQL ,執行后,再將結果映射成 Java 對象返回。相較于 Hibernate, Mybatis 因為可以編寫原生的 SQL ,也就是說,能夠嚴格控制 SQL 執行性能,靈活度高。但是靈活的前提是 MyBatis 無法做到數據庫無關性,如果需要實現支持多種數據庫的軟件則需要自定義多套 SQL 映射文件,工作量大。
? ? ? ?再來說說 Hibernate, 它對象/關系映射能力強,能做到數據庫無關性。如果用 Hibernate 開發,無需關系 SQL 編寫(不會寫 SQL 的人都可以操作數據庫),能節省很多代碼,提高效率。但是 Hibernate 的缺點是學習門檻高,要精通門檻更高,而且怎么設計 O/R 映射,在性能和對象模型之間如何權衡,以及怎樣用好 Hibernate 需要具有很強的經驗和能力才行。
? ? ? ?我覺得最后結合公司業務,選取最適合的框架,不要為了技術而技術,否則都是耍流氓。比如說,你所在的是相對來說較小的公司,數據量并不大,且公司開發人員的技術棧偏 Hibernate 多一些,推薦使用 JPA、Hibernate 這些無需手動編寫 SQL 的持久層框架,提高開發效率、版本迭代速度。如果說,你所在的是一家互聯網公司,用戶數較大,對相關 SQL 執行性能要求較為嚴格,則推薦使用 Mybatis。總之,按照用戶的需求在有限的資源環境下只要能做出維護性、擴展性良好的軟件架構都是好架構,所以框架只有適合才是最好。
#{}和${}的區別是什么???
這個問題比較基礎也比較經典、但是在面試中是基本必問的、?
#{}是預編譯處理,${}是字符串替換。
Mybatis?在處理#{}時,會將 sql 中的#{}替換為?號,調用 PreparedStatement 的 set 方法來賦值;
Mybatis?在處理${}時,就是把${}替換成變量的值。
使用#{}可以有效的防止 SQL 注入,提高系統安全性。
下面通過一個例子來說明明吧
大家都知道Mybatis 的Mapper.xml語句中parameterType向SQL語句傳參有兩種方式:#{}和${}
我們經常使用的是#{},一般解說是因為這種方式可以防止SQL注入,簡單的說#{}這種方式SQL語句是經過預編譯的,它是把#{}中間的參數轉義成字符串,舉個例子:
select * from student where student_name = #{name}?預編譯后,會動態解析成一個參數標記符?
select * from student where student_name = #{name}?而使用${}在動態解析時候,會傳入參數字符串
? select * from student where student_name = #{name}???當實體類中的屬性名和表中的字段名不一樣?,怎么辦?? ?
舉例說明:一種是在Mapper映射文件中使用resultMap來自定義映射規則
<!-- 自定義高級映射 --> <!-- namespace屬性:必須是接口的全類名 --> <mapper namespace="com.tt.mybatis.mapper.EmployeeMapper"><!-- id屬性:必須是接口中方法的方法名resultType屬性:必須是方法的返回值的全類名--><select id="getEmployeeById" resultMap="myMap">select * from employees where id = #{id}</select><!-- 自定義高級映射 --><resultMap type="com.tt.mybatis.entities.Employee" id="myMap"><!-- 映射主鍵 --><id column="id" property="id"/><!-- 映射其他列 --><result column="last_name" property="lastName"/><result column="email" property="email"/><result column="salary" property="salary"/><result column="dept_id" property="deptId"/></resultMap> </mapper>還有就是sql語句時起別名
<configuration><settings><!-- 開啟駝峰命名規則 ,可以將數據庫中的下劃線映射為駝峰命名例如:last_name可以映射為lastName--><setting name="mapUnderscoreToCamelCase" value="true"/></settings><environments default="development"><environment id="development"><transactionManager type="JDBC" /><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://localhost:3306/mybatis" /><property name="username" value="root" /><property name="password" value="root" /></dataSource></environment></environments><!-- 注冊映射文件 --><mappers><mapper resource="EmployeeMapper.xml" /></mappers>?模糊查詢 like 語句該怎么寫?? ?
舉例說明:在 Java 代碼中添加 sql 通配符。
string wildcardname = “%smi%”;list<name> names = mapper.selectlike(wildcardname); <select id=”selectlike”>select * from foo where bar like #{value}</select>另一種方式就是在 sql 語句中拼接通配符,但是可能會引起 sql 注入
string wildcardname = “smi”;list<name> names = mapper.selectlike(wildcardname); <select id=”selectlike”>select * from foo where bar like "%"#{value}"%"</select>?Mybatis Dao層?接口的工作原理是什么?Dao 接口里的方法,參數不同時,方法能重載嗎?
?舉例說明:? Dao接口就是Mapper接口,---可以基于注解的方式創建接口,接口內定義抽象方法;
public interface UserMapper {@Select("select * from users where id=#{id}")public User getUserById(int id);}接口的全限名,就是映射文件中的namespace的值:
<mapper namespace="com.mybatis.test3.orderMapper"> <select id="selectUser" parameterType="int" resultType="Order"> select * from users where id=#{id} </select> </mapper>接口的全名是映射文件中命名空間的值:
<mapper namespace="com.mybatis.test3.orderMapper"> <select id="selectUser" parameterType="int" resultType="Order"> select * from users where id=#{id} </select> </mapper>接口方法名(getUserById)是映射文件中MappedStatement中的id值(selectUser),接口方法中的參數是傳遞給SQL的參數(#{id} >>> #{id})。
Mapper接口沒有實現類。當調用接口方法時,將接口名稱+方法名稱與字符串連接作為鍵值,以唯一定位MappedStatement。例如:Com。Mybatis。Test2。usermap。只能找到com的名稱空間。Mybatis。Test2。UserMapper id = insertUser MappedStatement如下。
在Mybatis中,每個<select>, < INSERT >, <update>, and <delete>標記都被解析為一個MappedStatement對象。
關于重載和工作原理解釋
Dao接口中的2個方法不能被覆蓋,因為它是一個全名+方法名的保存和查找策略。
Dao接口的工作原理是JDK動態代理。Mybatis運行時,將使用JDK動態代理為Dao接口生成代理代理對象。
Mybatis 是如何進行分頁的?分頁插件的原理是什么?
? ? ?Mybatis 使用 RowBounds 對象進行分頁,它是針對 ResultSet 結果集執行的內存分頁,而非物理分頁。可以在?sql 內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可以使用分頁插件來完成物理分頁。下面看看Mybatis的如何進行分頁
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext resultContext = new DefaultResultContext();// 跳到offset位置,準備讀取skipRows(rsw.getResultSet(), rowBounds);// 讀取limit條數據while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) {ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null);Object rowValue = getRowValue(rsw, discriminatedResultMap);storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet());}}private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {// 直接定位rs.absolute(rowBounds.getOffset());}} else {// 只能逐條滾動到指定位置for (int i = 0; i < rowBounds.getOffset(); i++) {rs.next();}}}原理的話大家參考這篇文章MyBatis之分頁插件(PageHelper)工作原理
Mybatis 是如何將 sql 執行結果封裝為目標對象并返回的?都有哪些映射形式?
第一種方法是使用<resultMap>標記逐個定義數據庫列名和對象屬性名之間的映射。
第二種方法是使用SQL列的別名函數將列的別名作為對象屬性名寫入。
使用列名和屬性名之間的映射,Mybatis通過反射創建對象并使用反射對象的屬性逐個賦值并返回,如果找不到映射關系,則無法完成賦值。
Mybatis 如何執行批量插入?
-
首先,創建一個簡單的INSERT語句:
?然后在Java代碼中執行批量插入操作:
list < string > names = new arraylist(); names.add(“fred”); names.add(“barney”); names.add(“betty”); names.add(“wilma”);// 注意 executortype.batch sqlsession sqlsession =sqlsessionfactory.opensession(executortype.batch); try {namemapper mapper = sqlsession.getmapper(namemapper.class);for (string name: names) {mapper.insertname(name);}sqlsession.commit(); } catch (Exception e) {e.printStackTrace();sqlSession.rollback();throw e; } finally {sqlsession.close(); }?Mybatis 如何獲取自動生成的(主)鍵值?
?Mapper文件insert語句設置?? ?
useGeneratedKeys="true" keyProperty="id"Mybatis 在 mapper 中如何傳遞多個參數?
第一種方案?DAO層的函數方法?
Public User selectUser(String name,String area);對應的Mapper.xml配置文件
<select id="selectUser" resultMap="BaseResultMap" parameterType="java.lang.String"> select * from user_user_t where user_name = #{0} and user_area=#{1} </select>其中,#{0}代表接收的是dao層中的第一個參數,#{1}代表dao層中第二參數,更多參數一致往后加即可。
第二種Dao層的函數方法
Public User selectUser(@param(“userName”)Stringname,@param(“userArea”)String area);對應的Mapper.xml配置文件
<select id=" selectUser" resultMap="BaseResultMap"> select * from user_user_t where user_name = #{userName,jdbcType=VARCHAR} and user_area=#{userArea,jdbcType=VARCHAR} </select>個人覺得這種方法比較好,能讓開發者看到dao層方法就知道該傳什么樣的參數,比較直觀,個人推薦用此種方案。
Mybatis 動態 sql 有什么用?執行原理?有哪些動態 sql?
Mybatis 動態 sql 可以在 Xml 映射文件內,以標簽的形式編寫動態 sql,
執行原理是根據表達式的值?完成邏輯判斷并動態拼接?sql 的功能。
動態 sql有九種、具體是:trim | where | set | foreach | if | choose| when | otherwise | bind。
具體九種動態SQL舉例:
?if標簽
<!-- 查詢學生list,like姓名 --> ?<select id=" getStudentListLikeName " parameterType="StudentEntity" resultMap="studentResultMap"> ?SELECT * from STUDENT_TBL ST ??<if test="studentName!=null and studentName!='' "> ?WHERE ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%') ??</if> ?</select> ?where標簽
<!-- 查詢學生list,like姓名,=性別 --> <select id="getStudentListWhere" parameterType="StudentEntity" resultMap="studentResultMap"> SELECT * from STUDENT_TBL ST <where> <if test="studentName!=null and studentName!='' "> ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%') </if> <if test="studentSex!= null and studentSex!= '' "> AND ST.STUDENT_SEX = #{studentSex} </if> </where> </select>set標簽
<!-- 更新學生信息 --> <update id="updateStudent" parameterType="StudentEntity"> UPDATE STUDENT_TBL <set> <if test="studentName!=null and studentName!='' "> STUDENT_TBL.STUDENT_NAME = #{studentName}, </if> <if test="studentSex!=null and studentSex!='' "> STUDENT_TBL.STUDENT_SEX = #{studentSex}, </if> <if test="studentBirthday!=null "> STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday}, </if> <if test="classEntity!=null and classEntity.classID!=null and classEntity.classID!='' "> STUDENT_TBL.CLASS_ID = #{classEntity.classID} </if> </set> WHERE STUDENT_TBL.STUDENT_ID = #{studentID}; </update>trim標簽
<!-- 查詢學生list,like姓名,=性別 --> <select id="getStudentListWhere" parameterType="StudentEntity" resultMap="studentResultMap"> SELECT * from STUDENT_TBL ST <trim prefix="WHERE" prefixOverrides="AND|OR"> <if test="studentName!=null and studentName!='' "> ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%') </if> <if test="studentSex!= null and studentSex!= '' "> AND ST.STUDENT_SEX = #{studentSex} </if> </trim> </select>choose? when?otherwise標簽
<!-- 查詢學生list,like姓名、或=性別、或=生日、或=班級,使用choose --> <select id="getStudentListChooseEntity" parameterType="StudentEntity" resultMap="studentResultMap"> SELECT * from STUDENT_TBL ST <where> <choose> <when test="studentName!=null and studentName!='' "> ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%') </when> <when test="studentSex!= null and studentSex!= '' "> AND ST.STUDENT_SEX = #{studentSex} </when> <when test="studentBirthday!=null"> AND ST.STUDENT_BIRTHDAY = #{studentBirthday} </when> <when test="classEntity!=null and classEntity.classID !=null and classEntity.classID!='' "> AND ST.CLASS_ID = #{classEntity.classID} </when> <otherwise> </otherwise> </choose> </where> </select>?foreach
<select id="getStudentListByClassIDs" resultMap="studentResultMap"> SELECT * FROM STUDENT_TBL ST WHERE ST.CLASS_ID IN <foreach collection="list" item="classList" open="(" separator="," close=")"> #{classList} </foreach> </select>Mybatis 的 Xml 映射 文件 中,不同 的 Xml 映射 文件?,?id 是否 可以 重復 ??
不同的Xml映射文件?,如果配置了namespace,那么id可以重復;
如果沒有配置namespace,那么id不能重復;原因就是namespace+id是作為Map<String,?MapperStatement>的key使用的,如果沒有namespace,就剩下id,那么,id重復會導致數據互相覆蓋。
有了namespace,自然id就可以重復?,namespace不同?,namespace+id自然也就不同?。
Xml 映射文件中,除了常見的 select|insert|updae|delete 標簽之外,還有哪些標簽?
<resultMap>、<parameterMap>、<sql>、<include>、<selectKey> ,加上動態 sql 的 9 個標簽,其中 <sql> 為 sql 片段標簽,通過<include> 標簽引入 sql 片段, <selectKey> 為不支持自增的主鍵生成策略標簽。
為什么說 Mybatis 是半自動 ORM 映射工具?它與全自動的區別在哪里?
Hibernate屬于全自動ORM映射工具?,使用Hibernate查詢關聯對象或者關聯集合對象時,可以根據對象關系模型直接獲取?,所以它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,需要手動編寫sql來完成,所以?,稱之為半自動ORM映射工具。
Mybatis 的一對一、一對多的關聯查詢??
?一對一關聯查詢
<mapper namespace="com.lcb.mapping.userMapper"> <!--association 一對一關聯查詢 --> <select id="getClass" parameterType="int" resultMap="ClassesResultMap"> select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id} </select> <resultMap type="com.lcb.user.Classes" id="ClassesResultMap"> <!-- 實體類的字段名和數據表的字段名映射 --> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <association property="teacher" javaType="com.lcb.user.Teacher"> <id property="id" column="t_id"/> <result property="name" column="t_name"/> </association> </resultMap> </mapper>?一對多關聯查詢
<!--collection 一對多關聯查詢 --> <select id="getClass2" parameterType="int" resultMap="ClassesResultMap2"> select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id} </select> <resultMap type="com.lcb.user.Classes" id="ClassesResultMap2"> <id property="id" column="c_id"/> <result property="name" column="c_name"/> <association property="teacher" javaType="com.lcb.user.Teacher"> <id property="id" column="t_id"/> <result property="name" column="t_name"/> </association> <collection property="student" ofType="com.lcb.user.Student"> <id property="id" column="s_id"/> <result property="name" column="s_name"/> </collection> </resultMap>?MyBatis 實現一對一有幾種方式?具體怎么操作的?
有聯合查詢和嵌套查詢,
聯合查詢是幾個表聯合查詢,只查詢一次,通過在resultMap里面配置association節點配置一對一的類就可以完成;
嵌套查詢是先查一個表,根據這個表里面的結果的外鍵id,去再另外一個表里面查詢數據,也是通過association配置,但另外一個表的查詢通過select屬性配置
MyBatis 實現一對多有幾種方式,怎么操作的?
有聯合查詢和嵌套查詢。
聯合查詢是幾個表聯合查詢,只查詢一次,通過在resultMap里面的collection節點配置一對多的類就可以完成;嵌套查詢是先查一個表,根據這個表里面的結果的外鍵id,去再另外一個表里面查詢數據,也是通過配置collection,但另外一個表的查詢通過select節點配置。
Mybatis 是否支持延遲加載?如果支持,它的實現原理是什么?
? ? ? ? ? Mybatis僅支持association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,可以配置是否啟用延遲加載lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB創建目標對象的代理對象,當調用目標方法時,進入攔截器方法,比如調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那么就會單獨發送事先保存好的查詢關聯B對象的sql,把B查詢上來,然后調用a.setB(b),于是a的對象b屬性就有值了,接著完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。
當然了,不光是Mybatis,幾乎所有的包括Hibernate,支持延遲加載的原理都是一樣的。
Mybatis 的一級、二級緩存
一級緩存:
? ? ? Mybatis支持緩存,但在沒有配置的情況下,默認情況下它只啟用一級緩存。級別1緩存只對相同的SqlSession啟用。因此,如果SQL參數一模一樣,我們使用相同的SqlSession對象調用映射方法,通常只執行SQL一次,因為第一個查詢使用SelSession MyBatis將把它放在緩存中,和將來查詢,如果沒有聲明需要刷新,如果緩存中沒有,SqlSession將獲取當前緩存的數據,并且不會再次向數據庫發送SQL
二級緩存:
MyBatis的二級緩存是Application級別的緩存,它可以提高對數據庫查詢的效率,以提高應用的性能。二級緩存與一級緩存其機制相同,默認也是采用PerpetualCache,HashMap存儲,不同在于其存儲作用域為Mapper(Namespace),并且可自定義存儲源,如Ehcache。默認不打開二級緩存,要開啟二級緩存,使用二級緩存屬性類需要實現Serializable序列化接口(可用來保存對象的狀態),可在它的映射文件中配置<cache/>;
對于緩存數據更新機制,當某一個作用域(一級緩存Session/二級緩存Namespaces)的進行了C/U/D操作后,默認該作用域下所有select中的緩存將被clear。
什么是 MyBatis 的接口綁定?有哪些實現方式?
? ? ? 接口綁定,就是在MyBatis中任意定義接口,然后把接口里面的方法和SQL語句綁定,我們直接調用接口方法就可以,這樣比起原來了SqlSession提供的方法我們可以有更加靈活的選擇和設置。
接口綁定有兩種實現方式,一種是通過注解綁定,就是在接口的方法上面加上@Select、@Update等注解,里面包含Sql語句來綁定;
另外一種就是通過xml里面寫SQL來綁定,在這種情況下,要指定xml映射文件里面的namespace必須為接口的全路徑名。
當Sql語句比較簡單時候,用注解綁定,當SQL語句比較復雜時候,用xml綁定,一般用xml綁定的比較多。
使用 MyBatis 的 mapper 接口調用時有哪些要求?
Mapper接口方法名和mapper.xml中定義的每個sql的id相同;
Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql的parameterType的類型相同;
Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同;
Mapper.xml文件中的namespace即是mapper接口的類路徑。
Mapper 編寫的幾種實現方式?
第一、接口實現類繼承 SqlSessionDaoSupport:使用此種方法需要編寫mapper 接口,mapper 接口實現類、mapper.xml 文件。
1、在 sqlMapConfig.xml 中配置 mapper.xml 的位置
<mappers><mapper resource="mapper.xml 文件的地址" /><mapper resource="mapper.xml 文件的地址" /></mappers>2、定義 mapper 接口.
3、實現類集成 SqlSessionDaoSupportmapper 方法中可以this.getSqlSession()進行數據增刪改查。
4、spring 配置
<bean id=" " class="mapper 接口的實現"><property name="sqlSessionFactory" ref="sqlSessionFactory"></property></bean>第二、使用 org.mybatis.spring.mapper.MapperFactoryBean:
1、在 sqlMapConfig.xml 中配置 mapper.xml 的位置,如果 mapper.xml 和mappre 接口的名稱相同且在同一個目錄,這里可以不用配置
<mappers><mapper resource="mapper.xml 文件的地址" /><mapper resource="mapper.xml 文件的地址" /></mappers>2、定義 mapper 接口:
2.1、mapper.xml 中的 namespace 為 mapper 接口的地址
2.2、mapper 接口中的方法名和 mapper.xml 中的定義的 statement 的 id 保持一致
2.3、Spring 中定義
<bean id="" class="org.mybatis.spring.mapper.MapperFactoryBean"><property name="mapperInterface" value="mapper 接口地址" /><property name="sqlSessionFactory" ref="sqlSessionFactory" /></bean>第三、使用 mapper 掃描器:
1、mapper.xml 文件編寫:mapper.xml 中的 namespace 為 mapper 接口的地址;mapper 接口中的方法名和 mapper.xml 中的定義的 statement 的 id 保持一致;如果將 mapper.xml 和 mapper 接口的名稱保持一致則不用在 sqlMapConfig.xml中進行配置。
2、定義 mapper 接口:注意 mapper.xml 的文件名和 mapper 的接口名稱保持一致,且放在同一個目錄
3、配置 mapper 掃描器:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="mapper 接口包地址"></property><property name="sqlSessionFactoryBeanName"value="sqlSessionFactory"/></bean>4、使用掃描器后從 spring 容器中獲取 mapper 的實現對象
簡述 Mybatis 的插件運行原理,以及如何編寫一個插件?
? ? ? Mybatis只能為ParameterHandler, ResultSetHandler,StatementHandler和Executor接口。Mybatis使用JDK的動態生成為需要被攔截的接口生成代理對象,以便在執行這4種類型時實現接口方法攔截Invoke (), Invoke (), Invoke ()、當然,方法只會攔截那些您指定需要攔截的方法。
編寫插件:實現Mybatis的Interceptor接口
public interface Interceptor {Object intercept(Invocation invocation) throws Throwable;default Object plugin(Object target) {return Plugin.wrap(target, this);}default void setProperties(Properties properties) {// NOP} }復制intercept()方法插件會編寫注解來指定要攔截接口的哪些方法。記住不要忘記配置文本配置你編寫的插件哈。
public class Invocation {private final Object target;private final Method method;private final Object[] args;public Invocation(Object target, Method method, Object[] args) {this.target = target;this.method = method;this.args = args;}public Object getTarget() {return target;}public Method getMethod() {return method;}public Object[] getArgs() {return args;}public Object proceed() throws InvocationTargetException, IllegalAccessException {return method.invoke(target, args);}}方法說明:這個東西包含了四個概念:
- target?攔截的對象
- method?攔截target中的具體方法,也就是說Mybatis插件的粒度是精確到方法級別的。
- args?攔截到的參數。
- proceed?執行被攔截到的方法,你可以在執行的前后做一些事情。
精彩推送:
Springboot項目畢設實戰100套
JavaWeb項目畢設實戰100套
JavaSwing項目實戰100套
總結:
好了,今天就分享到這里啦、這篇文章總體來說對于學習或面試來說都是比較不錯的、文章中涉及的知識點都比較關鍵。
另外需要白嫖java學習資料包括《JVM、Netty、Mysql、Mybatis、Redis、Dubbo、Nginx、設計模式》等10G資料禮包、可以看我主頁或私信博主都行。
打卡Java更新?15?/ 100天
大家可以點贊、收藏、關注、評論我啦 、下面的投票也可以積極互動起來喲
總結
以上是生活随笔為你收集整理的Java--Mybatis万字长文经典面试题王者笔记《收藏版》的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 解死锁权限,讲解Oracl
- 下一篇: linux进程监控自动重启,Linux监