Java?Mybatis查詢數(shù)據(jù)庫舉例詳解
前言
經(jīng)過前面的學習Spring系列的操作已經(jīng)差不多了,接下來我們繼續(xù)學習更加重要的知識,將前端傳遞的參數(shù)存儲起來,或者查詢數(shù)據(jù)庫里面的數(shù)據(jù)
1. MyBatis 是什么?
MyBatis是款優(yōu)秀的持久層框架,它支持自定義SQL、存儲過程以及高級映射。MyBatis幾乎祛除了所有的JDBC代碼以及設(shè)置參數(shù)和獲取結(jié)果集的操作。MyBatis可以通過簡單的XML或者注解來配置和映射原始類型、接口和Java POJO為數(shù)據(jù)庫中的記錄
簡單來說MyBatis是簡單完成程序和數(shù)據(jù)庫交互的工具,也就是更簡單的操作和讀取數(shù)據(jù)庫的工具
2. 為什么要學習MyBatis?
對于后端程序員來說,程序是由以下兩個程序組成的:
- 后端程序
- 數(shù)據(jù)庫
而這兩個重要的組成部分要通訊,就要依靠數(shù)據(jù)庫連接工具,那么數(shù)據(jù)庫連接工具有哪些?比如JDBC還有今天我們要介紹的MyBatis。既然已經(jīng)有了JDBC,為什么還要學習MyBatis?這是因為JDBC操作太繁瑣了,我們來回顧一下JDBC的操作流程:
- 創(chuàng)建數(shù)據(jù)庫連接池
DataSource
- 通過
DataSource
獲取數(shù)據(jù)庫連接Connection
- 編寫要帶?的占位符的SQL語句
- 通過
Connection
及SQL創(chuàng)建操作命令對象Statement
- 替換占位符:指定要替換的數(shù)據(jù)庫字段類型,占位符索引及要替換的值
- 使用
Statement
執(zhí)行SQL語句 - 查詢操作:返回結(jié)果集
ResultSet
,更新操作:返回更新的數(shù)量 - 處理結(jié)果集
- 釋放資源
3. 怎么學MyBatis?
MyBatis的學習只分為兩部分:
- 配置MyBatis開發(fā)環(huán)境
- 使用MyBatis模式和語法操作數(shù)據(jù)庫
4. 第一個MyBatis查詢
開始搭建MyBatis之前,我們需要先來看看它在整個框架之中的地位
MyBatis也是一個ORM框架,ORM即對象關(guān)系映射。在面向?qū)ο缶幊陶Z言當中,講關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)與對象建立起映射關(guān)系,進行自動完成數(shù)據(jù)與對象的相互轉(zhuǎn)換
- 將輸入數(shù)據(jù)(即傳入對象)+ SQL映射原生SQL
- 將結(jié)果集映射為返回對象,即輸出對象
ORM把數(shù)據(jù)庫映射為對象:
- 數(shù)據(jù)表—》 類
- 記錄—》對象
- 字段—》對象的屬性
一般的ORM框架,會將數(shù)據(jù)庫模型的每一張表都映射為一個Java類
也就是說使用MyBatis可以像操作對象一樣操作數(shù)據(jù)庫中的表,可以實現(xiàn)對象和數(shù)據(jù)表之間的轉(zhuǎn)換,我們接下來看看MyBatis的使用
4.1 創(chuàng)建數(shù)據(jù)庫和表
使用MyBatis的方式來讀取用戶表當中的所有用戶,我們使用個人博客的數(shù)據(jù)包。
-- 創(chuàng)建數(shù)據(jù)庫 drop database if exists mycnblog; create database mycnblog DEFAULT CHARACTER SET utf8mb4; -- 使?數(shù)據(jù)數(shù)據(jù) use mycnblog; -- 創(chuàng)建表[?戶表] drop table if exists userinfo; create table userinfo( id int primary key auto_increment, username varchar(100) not null, password varchar(32) not null, photo varchar(500) default '', createtime datetime default now(), updatetime datetime default now(), `state` int default 1 ) default charset 'utf8mb4'; -- 創(chuàng)建?章表 drop table if exists articleinfo; create table articleinfo( id int primary key auto_increment, title varchar(100) not null, content text not null, createtime datetime default now(), updatetime datetime default now(), uid int not null, rcount int not null default 1, `state` int default 1 )default charset 'utf8mb4'; -- 創(chuàng)建視頻表 drop table if exists videoinfo; create table videoinfo( vid int primary key, `title` varchar(250), `url` varchar(1000), createtime datetime default now(), updatetime datetime default now(), uid int )default charset 'utf8mb4'; -- 添加?個?戶信息 INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES (1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1) ; -- ?章添加測試數(shù)據(jù) insert into articleinfo(title,content,uid) values('Java','Java正?',1); -- 添加視頻 insert into videoinfo(vid,title,url,uid) values(1,'java title','http://ww w.baidu.com',1);
4.2 添加MyBatis框架支持
添加MyBatis框架支持分為兩種情況:一種情況是對之前的Spring項目進行升級,另一種情況是創(chuàng)建一個全新的MyBatis和Spring Boot項目
擴展:在老項目當中快速的添加框架,更簡單的操作是使用EditStarters插件
4.3 配置連接字符串和MyBatis
此步驟需要進行兩項設(shè)置,數(shù)據(jù)庫連接字符串設(shè)置和MyBatis的XML文件配置
4.3.1 配置連接數(shù)據(jù)庫
spring: datasource: url: jdbc:mysql://127.0.0.1:3306/mycnblog?characterEncoding=utf8&&useSSL=false username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver
注意事項:
如果使用mysql-connector-java是5.x之前使用的
con.mysql.jdbc.Driver
如果大于5.x使用的是com.mysql.cj.jdbc.Driver
配置MyBatis中的XML路徑
MyBatis的XML中保存的是查詢數(shù)據(jù)庫的具體操作的SQL,配置如下:
mybatis: mapper-locations: classpath:mybatis/**Mapper.xml
4.4 添加業(yè)務(wù)代碼
下面按照后端開發(fā)的工程思路,也就是下面的流程來實現(xiàn)MyBatis查詢所有用戶的功能:
4.4.1 添加實體類
先添加用戶的實體類:
import lombok.Data; import java.util.Date; @Data public class User { private Integer id; private String username; private String password; private String photo; private Date createTime; private Date updateTime; }
4.4.2 添加Mapper接口
數(shù)據(jù)持久層的接口定義:
@Mapper public interface UserMapper { public UserInfo getUserById(@Param("id") Integer id); public void add(@RequestBody UserInfo userInfo); }
4.4.3 添加UserMapper.xml
數(shù)據(jù)持久層的實現(xiàn),MyBatis的固定格式:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.mapper.UserMapper"> <select id="getUserById" resultType="com.example.demo.model.UserInfo"> select * from userinfo where id = #{id} </select> </mapper>
- 標簽:需要指定namespace屬性,表示命名空間,值為mapper接口的全限定名,包括包名.類名
<select>
標簽:是用來執(zhí)行數(shù)據(jù)庫的查詢操作的id:是和interface中定義的方法名稱是一樣的,表示對接口的具體實現(xiàn)方法
resultType:是返回的數(shù)據(jù)類型,也就是開頭定義的實體類
4.4.4 添加Service
服務(wù)層代碼如下:
@Service public class UserService { @Resource private UserMapper userMapper; public UserInfo getUserById(Integer id) { return userMapper.getUserById(id); } }
4.4.5 添加Controller
控制層的代碼實現(xiàn)如下:
@Controller @ResponseBody public class UserController { @Resource private UserService userService; @RequestMapping("/getuserbyid") public UserInfo getUserById(Integer id) { return userService.getUserById(id); } }
5. 增、刪、改操作
5.1 增加用戶的操作
<insert id="add"> insert into userinfo(username, password, photo) values (#{username}, #{password}, #{photo}) </insert> <insert id="getId" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> insert into userinfo(username, password, photo) values (#{username}, #{password}, #{photo}) </insert>
- useGeneratedKeys: 這會令MyBatis使用JDBC的getGeneratedKeys 方法取出由數(shù)據(jù)庫內(nèi)部生成的主鍵。(像MySQL和SQL service這樣的關(guān)系型數(shù)據(jù)庫關(guān)系系統(tǒng)自增主鍵)默認值是:false
- keyColumn: 設(shè)置生成建在表中的列名,在某些數(shù)據(jù)庫當中,當主鍵的列不是第一列的時候,是必須設(shè)置的。如果生成列不止一個,可以用逗號分割各個屬性名稱
- keyProperty:指定能夠唯一
5.2 刪除用戶的操作
<delete id="del"> delete from userinfo where id = #{id} </delete>
5.3 修改用戶操作
<update id="update"> update userinfo set username = #{name} where id = #{id} </update>
6. 查詢操作
6.1 單表查詢
controller代碼如下:
@RequestMapping("/getuserbyid") public UserInfo getUserById(Integer id) { return userService.getUserById(id); }
Mapper.xml實現(xiàn)代碼如下:
<select id="getUserById" resultType="com.example.demo.model.UserInfo"> select * from userinfo where id = #{id} </select>
6.1.1 參數(shù)占位符 #{} 和 ${}
- #{} :預編譯處理
- ${}:字符直接替換
預編譯處理是指:MyBatis在處理#{}時,會將SQL中的#{}替換為?,使用statement的set方法來賦值。直接替換:是MyBatis在處理 時,就是把 {}時,就是把 時,就是把{}替換成變量的值
6.1.2 $優(yōu)點
使用${}可以實現(xiàn)排序查詢,而是用#{}就不能實現(xiàn)排序查詢,因為當使用#{}查詢時,如果傳遞的值為String則會加引號,就會導致SQL錯誤。
6.1.3 SQL 注入問題
<select id="isLogin" resultType="com.example.demo.model.User"> select * from userinfo where username='${name}' and password='${pwd}' </select>
結(jié)論:用于查詢的字段,盡量使用#{}預查詢的方式
6.1.4 like查詢
like使用#{}
報錯,這個時候不能使用${}
,可以考慮使用MySQL內(nèi)置的函數(shù)concat()來處理,實現(xiàn)代碼如下:
<select id="findUserByName3" resultType="com.example.demo.model.User"> select * from userinfo where username like concat('%',#{username},'%'); </select>
concat可以連接字符。
6.2 多表查詢
如果增、刪、改返回影響的行數(shù),那么在mapper.xml中可以不設(shè)置返回的類型的。但是即使是最簡單的查詢,也要設(shè)置返回類型否則就會出現(xiàn)錯誤。
也就是說**對于<select>
查詢標簽,至少存在兩個屬性:
- id 屬性:用于標識實現(xiàn)接口的那個方法
- 結(jié)果映射屬性:結(jié)果映射有兩種實現(xiàn)標簽:
<resultType
和<resultMap
6.2.1 返回類型
絕大多數(shù)查詢場景可以使用resultType進行返回,如下代碼所示:
<select id="getNameById" resultType="java.lang.String"> select username from userinfo where id=#{id} </select>
它的優(yōu)點就是使用方便、直接定義到某個實體類就可以
6.2.2 返回字典映射:resultMap
resultMap使用場景:
- 字段名稱和程序中的屬性名稱不相同的情況,可以使用resultMap配置映射
- 一對一和多對一關(guān)系可以使用resultMap映射并查詢數(shù)據(jù)
字段名和屬性名不同的情況
<resultMap id="BaseMap" type="com.example.demo.model.User"> <id column="id" property="id"></id> <result column="username" property="username"></result> <result column="password" property="pwd"></result> </resultMap> <select id="getUserById" resultMap="com.example.demo.mapper.UserMapper.BaseMap"> select * from userinfo where id=#{id} </select>
6.2.3 多表查詢
在多表查詢的時候,如果使用resultMap標簽,在一個類中包含了另一個對象是查詢不出來包含的對象的。如下圖所示:
此時我們就需要使用特殊手段來實現(xiàn)聯(lián)表查詢了。
6.2.3.1 一對一的映射
一對一映射要使用<association>
標簽,具體實現(xiàn)如下所示:一篇文章只能對應(yīng)一個作者
<resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo"> <id column="id" property="id"></id> <result column="title" property="title"></result> <result column="content" property="content"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> <result column="uid" property="uid"></result> <result column="rcount" property="rcount"></result> <result column="state" property="state"></result> <association property="userInfo" resultMap="com.example.demo.mapper.UserMapper.BaseMap" columnPrefix="u_"> </association> </resultMap> <select id="getArticleById" resultMap="BaseMap"> select a.*, u.id u_id, u.username u_username, u.password u_password from articleinfo a left join userinfo u on a.uid = u.id where a.id = #{id} </select>
以上使用<assciation>
標簽,表示一對一的結(jié)果映射:
- property屬性:指定Article中對應(yīng)的屬性,即用戶
- resultMap屬性:指定關(guān)聯(lián)的結(jié)果集映射,將基于該映射配置來組織用戶數(shù)據(jù)
- columnPrefix屬性:綁定一對一對象時,是通過columnPrefix+assoction.result.colmn來映射結(jié)果集字段
注意:columnPrefix屬性不能省略,如果省略當聯(lián)表中有相同的字段,那么會導致查詢出錯
6.2.3.2 一對多的映射
一對多需要使用<collection>
標簽,用法和<association>
相同,如下所示:
<resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo"> <id column="id" property="id"></id> <result column="title" property="title"></result> <result column="content" property="content"></result> <result column="createtime" property="createtime"></result> <result column="updatetime" property="updatetime"></result> <result column="uid" property="uid"></result> <result column="rcount" property="rcount"></result> <result column="state" property="state"></result> <association property="userInfo" resultMap="com.example.demo.mapper.UserMapper.BaseMap" columnPrefix="u_"> </association> </resultMap> <select id="getArticleById" resultMap="BaseMap"> select a.*, u.id u_id, u.username u_username, u.password u_password from articleinfo a left join userinfo u on a.uid = u.id where a.id = #{id} </select>
7. 復雜情況
動態(tài)SQL是MyBatis的強大特性之一,能夠完成不同條件下不同的sql拼接
7.1 <if>標簽
在注冊的時候,我們可能遇到這樣一個問題。注冊分為兩個字段:必填字段和非必傳字段,那如果在添加用戶的時候又不確定的字段傳入,程序應(yīng)該如何實現(xiàn)?
這個時候我們就需要使用動態(tài)標簽了。
<insert id="add2"> insert into userinfo(username, password <if test="photo != null"> ,photo </if>) values (#{username}, #{password} <if test="photo != null"> ,#{photo} </if> ); </insert>
注意test中的,是傳入對象的屬性,不是數(shù)據(jù)庫字段
7.2 <trim>標簽
之前的插入功能,只是有一個字段為可選項,如果所有字段都是非必選項,就需要考慮用標簽結(jié)合標簽,對多個字段都采用動態(tài)生成的方式。
標簽當中有如下屬性:
- prefix: 表示整個語句塊,以prefix值為前綴
- suffix:表示整個語句塊,以suffix的值為后綴
- prefixOverrides:表示整個語句塊要去除的前綴
- suffixOverrides:表示整個語句塊要去除的后綴
使用方法如下:
<insert id="add3"> insert into userinfo <trim prefix="(" suffix=")" suffixOverrides=","> <if test="username != null"> username, </if> <if test="password != null"> password, </if> <if test="photo != null"> photo </if> values <trim prefix="(" suffix=")" suffixOverrides=","> <if test="username != null"> #{username}, </if> <if test="password != null"> #{password}, </if> <if test="photo != null"> #{photo} </if> </trim> </trim> </insert>
以上SQL動態(tài)解析時,會將第一個trim部分如下處理:
- 基于
prefix
配置,開始加上( - 基于
suffix
配置,結(jié)束部分加上) - 多個if組織的語句都以, 結(jié)尾,在最后拼接好的字符串還會以,結(jié)尾會基于
suffixOverrides
配置去掉最后一個, - if 中的test是傳入對象的屬性
7.3 <where>標簽
傳入對象時,根據(jù)屬性做where條件查詢,用戶對象中屬性不為null,都為查詢條件。
<select id="getUserById" resultMap="BaseMap"> select * from userinfo <where> <if test="id != null"> id = #{id} </if> </where> </select>
7.4 <set>標簽
根據(jù)傳入的用戶對象屬性來更新用戶數(shù)據(jù),可以使用標簽來指定動態(tài)內(nèi)容
<update id="updateById" parameterType="org.example.model.User"> update user <set> <if test="username != null"> username=#{username}, </if> <if test="password != null"> password=#{password}, </if> <if test="nickname != null"> nickname=#{nickname}, </if> <if test="sex != null"> sex=#{sex}, </if> <if test="birthday != null"> birthday=#{birthday}, </if> <if test="head != null"> head=#{head}, </if> <if test="createTime != null"> create_time=#{createTime}, </if> </set> where id=#{id} </update>
7.5 <foreach>標簽
對集合進行遍歷時, 可以使用該標簽。<foreach>
標簽有以下屬性。
- collection:綁定方法參數(shù)中的集合,如List、Set、Map或數(shù)組對象
- item:遍歷時的每一個對象
- open:語句塊開頭的字符串
- close:語句塊結(jié)束時的字符串
總結(jié)
到此這篇關(guān)于Java Mybatis查詢數(shù)據(jù)庫的文章就介紹到這了,更多相關(guān)Java Mybatis查詢數(shù)據(jù)庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot配置嵌入式Servlet容器和使用外置Servlet容器的教程圖解
這篇文章主要介紹了SpringBoot配置嵌入式Servlet容器和使用外置Servlet容器的教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07SpringBoot實現(xiàn)devtools實現(xiàn)熱部署過程解析
這篇文章主要介紹了SpringBoot實現(xiàn)devtools實現(xiàn)熱部署過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-03-03SpringBoot+MDC實現(xiàn)鏈路調(diào)用日志的方法
MDC是 log4j 、logback及l(fā)og4j2 提供的一種方便在多線程條件下記錄日志的功能,這篇文章主要介紹了SpringBoot+MDC實現(xiàn)鏈路調(diào)用日志,需要的朋友可以參考下2022-12-12java(swing)+ mysql實現(xiàn)學生信息管理系統(tǒng)源碼
這篇文章主要分享了java mysql實現(xiàn)學生信息管理系統(tǒng)的源碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11使用.NET Core3.0創(chuàng)建一個Windows服務(wù)的方法
這篇文章主要介紹了使用.NET Core3.0創(chuàng)建一個Windows服務(wù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04使用RestTemplate訪問https實現(xiàn)SSL請求操作
這篇文章主要介紹了使用RestTemplate訪問https實現(xiàn)SSL請求操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10