回顧上一章:MyBatis02:CRUD操作及配置解析
查詢爲null問題
要解決的問題:屬性名和字段名不一致
環境:新建一個項目,將之前的項目拷貝過來
1、查看之前的數據庫的字段名
2、Java中的實體類設計
public class User {
private int id; //id
private String name; //姓名
private String password; //密碼和數據庫不一樣!
//構造
//set/get
//toString()
}
3、接口
//根據id查詢用戶
User selectUserById(int id);
4、mapper映射文件
<select id="selectUserById" resultType="user">
select * from user where id = #{id}
</select>
5、測試
@Test
public void testSelectUserById() {
SqlSession session = MybatisUtils.getSession(); //獲取SqlSession連接
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
session.close();
}
結果:
-
User{id=1, name='狂神', password='null'}
-
查詢出來發現 password 爲空 . 說明出現了問題!
分析:
-
select * from user where id = #{id} 可以看做
select id,name,pwd from user where id = #{id}
-
mybatis會根據這些查詢的列名(會將列名轉化爲小寫,數據庫不區分大小寫) , 去對應的實體類中查找相應列名的set方法設值 , 由於找不到setPwd() , 所以password返回null ; 【自動映射】
解決方案
方案一:爲列名指定別名 , 別名和java實體類的屬性名一致 .
<select id="selectUserById" resultType="User">
select id , name , pwd as password from user where id = #{id}
</select>
方案二:使用結果集映射->ResultMap 【推薦】
<resultMap id="UserMap" type="User">
<!-- id爲主鍵 -->
<id column="id" property="id"/>
<!-- column是數據庫表的列名 , property是對應實體類的屬性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
ResultMap
自動映射
-
resultMap
元素是 MyBatis 中最重要最強大的元素。它可以讓你從 90% 的 JDBCResultSets
數據提取代碼中解放出來。 -
實際上,在爲一些比如連接的複雜語句編寫映射代碼的時候,一份
resultMap
能夠代替實現同等功能的長達數千行的代碼。 -
ResultMap 的設計思想是,對於簡單的語句根本不需要配置顯式的結果映射,而對於複雜一點的語句只需要描述它們的關係就行了。
你已經見過簡單映射語句的示例了,但並沒有顯式指定 resultMap
。比如:
<select id="selectUserById" resultType="map">
select id , name , pwd
from user
where id = #{id}
</select>
上述語句只是簡單地將所有的列映射到 HashMap
的鍵上,這由 resultType
屬性指定。雖然在大部分情況下都夠用,但是 HashMap 不是一個很好的模型。你的程序更可能會使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 對象)作爲模型。
ResultMap
最優秀的地方在於,雖然你已經對它相當瞭解了,但是根本就不需要顯式地用到他們。
手動映射
1、返回值類型爲resultMap
<select id="selectUserById" resultMap="UserMap">
select id , name , pwd from user where id = #{id}
</select>
2、編寫resultMap,實現手動映射!
<resultMap id="UserMap" type="User">
<!-- id爲主鍵 -->
<id column="id" property="id"/>
<!-- column是數據庫表的列名 , property是對應實體類的屬性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
如果世界總是這麼簡單就好了。但是肯定不是的,數據庫中,存在一對多,多對一的情況,我們之後會使用到一些高級的結果集映射,association,collection這些,我們將在之後講解,今天你們需要把這些知識都消化掉纔是最重要的!理解結果集映射的這個概念!
分頁的幾種方式
日誌工廠
思考:我們在測試SQL的時候,要是能夠在控制檯輸出 SQL 的話,是不是就能夠有更快的排錯效率?
如果一個 數據庫相關的操作出現了問題,我們可以根據輸出的SQL語句快速排查問題。
對於以往的開發過程,我們會經常使用到debug模式來調節,跟蹤我們的代碼執行過程。但是現在使用Mybatis是基於接口,配置文件的源代碼執行過程。因此,我們必須選擇日誌工具來作爲我們開發,調節程序的工具。
Mybatis內置的日誌工廠提供日誌功能,具體的日誌實現有以下幾種工具:
-
SLF4J
-
Apache Commons Logging
-
Log4j 2
-
Log4j
-
JDK logging
具體選擇哪個日誌實現工具由MyBatis的內置日誌工廠確定。它會使用最先找到的(按上文列舉的順序查找)。如果一個都未找到,日誌功能就會被禁用。
標準日誌實現
指定 MyBatis 應該使用哪個日誌記錄實現。如果此設置不存在,則會自動發現日誌記錄實現。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
測試,可以看到控制檯有大量的輸出!我們可以通過這些輸出來判斷程序到底哪裏出了Bug
Log4j
簡介:
-
Log4j是Apache的一個開源項目
-
通過使用Log4j,我們可以控制日誌信息輸送的目的地:控制檯,文本,GUI組件....
-
我們也可以控制每一條日誌的輸出格式;
-
通過定義每一條日誌信息的級別,我們能夠更加細緻地控制日誌的生成過程。最令人感興趣的就是,這些可以通過一個配置文件來靈活地進行配置,而不需要修改應用的代碼。
使用步驟:
1、導入log4j的包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、配置文件編寫
#將等級爲DEBUG的日誌信息輸出到console和file這兩個目的地,console和file的定義在下面的代碼
log4j.rootLogger=DEBUG,console,file
#控制檯輸出的相關設置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件輸出的相關設置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日誌輸出級別
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3、setting設置日誌實現
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
4、在程序中使用Log4j進行輸出!
//注意導包:org.apache.log4j.Logger
static Logger logger = Logger.getLogger(MyTest.class);
@Test
public void selectUser() {
logger.info("info:進入selectUser方法");
logger.debug("debug:進入selectUser方法");
logger.error("error: 進入selectUser方法");
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.selectUser();
for (User user: users){
System.out.println(user);
}
session.close();
}
5、測試,看控制檯輸出!
-
使用Log4j 輸出日誌
-
可以看到還生成了一個日誌的文件 【需要修改file的日誌級別】
limit實現分頁
思考:爲什麼需要分頁?
在學習mybatis等持久層框架的時候,會經常對數據進行增刪改查操作,使用最多的是對數據庫進行查詢操作,如果查詢大量數據的時候,我們往往使用分頁進行查詢,也就是每次處理小部分數據,這樣對數據庫壓力就在可控範圍內。
使用Limit實現分頁
#語法
SELECT * FROM table LIMIT stratIndex,pageSize
SELECT * FROM table LIMIT 5,10; // 檢索記錄行 6-15
#爲了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個參數爲 -1:
SELECT * FROM table LIMIT 95,-1; // 檢索記錄行 96-last.
#如果只給定一個參數,它表示返回最大的記錄行數目:
SELECT * FROM table LIMIT 5; //檢索前 5 個記錄行
#換句話說,LIMIT n 等價於 LIMIT 0,n。
步驟:
1、修改Mapper文件
<select id="selectUser" parameterType="map" resultType="user">
select * from user limit #{startIndex},#{pageSize}
</select>
2、Mapper接口,參數爲map
//選擇全部用戶實現分頁
List<User> selectUser(Map<String,Integer> map);
3、在測試類中傳入參數測試
-
推斷:起始位置 = (當前頁面 - 1 ) * 頁面大小
//分頁查詢 , 兩個參數startIndex , pageSize
@Test
public void testSelectUser() {
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int currentPage = 1; //第幾頁
int pageSize = 2; //每頁顯示幾個
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("startIndex",(currentPage-1)*pageSize);
map.put("pageSize",pageSize);
List<User> users = mapper.selectUser(map);
for (User user: users){
System.out.println(user);
}
session.close();
}
RowBounds分頁
我們除了使用Limit在SQL層面實現分頁,也可以使用RowBounds在Java代碼層面實現分頁,當然此種方式作爲了解即可。我們來看下如何實現的!
步驟:
1、mapper接口
//選擇全部用戶RowBounds實現分頁
List<User> getUserByRowBounds();
2、mapper文件
<select id="getUserByRowBounds" resultType="user">
select * from user
</select>
3、測試類
在這裏,我們需要使用RowBounds類
@Test
public void testUserByRowBounds() {
SqlSession session = MybatisUtils.getSession();
int currentPage = 2; //第幾頁
int pageSize = 2; //每頁顯示幾個
RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);
//通過session.**方法進行傳遞rowBounds,[此種方式現在已經不推薦使用了]
List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds", null, rowBounds);
for (User user: users){
System.out.println(user);
}
session.close();
}
PageHelper
瞭解即可,可以自己嘗試使用
官方文檔:https://pagehelper.github.io/
在MyBatisPlus中,我們也講解到了分頁實現,所以實現方式很多,看自己的理解和熟練程度進行掌握即可!
會了簡單的結果集映射,後面我們就可以實現一對多和多對一操作了