1,配置相關
我們上一期詳細講了一下使用注解來實現操作數據庫的方式,我們今天使用xml來實現,有同學可能有疑問,使用注解挺方便呀,為啥還要注解呀,先來說一下注解我感覺挺麻煩的,但是我們后面要學動態SQL,注解就要要重寫一遍xml到注解,更麻煩了,所以我們還是要學這個,xml和注解是可以共存的,所以不怕沖突;
我們先來準備工作:
根據數據庫創建model字段,
@Data
public class userInfo {private Integer id;private String userName;private String password;private Integer deleteFlag;private Date createTime;private Date updateTime;
}
?
下一個這個插件:
寫yml配置:
?
# 數據庫連接配置datasource:url: jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:configuration:map-underscore-to-camel-case: true #配置駝峰?動轉換log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql語句mapper-locations: classpath:mapper/**Mapper.xml
最后一行就是yml的配置了,這一行的意思是我們在resources路徑下創建一個mapper包,里面放一個~~名后后綴是Mapper.xml的文件,這個可以自己起名;
之后在xml文件中寫:
<?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="org.example.java_test_6_7.mapper.UserMapper"></mapper>
?這個namespace對應的是自己項目名,后面.mapper.UserMapper對應的是這塊
?下面我們點擊那個小藍鳥,如果能跳轉到小紅鳥那,就說明我們跳轉成功了;、
2,CRUD
1,增
@Mapper
public interface UserMapper {void insertUserInfo(UserInfo userInfo);
}
之后在mapper中寫:(可以直接alt+enter生成)
<insert id="insertUserInfo"></insert>
?
注意這個要頂格寫
<insert id="insertUserInfo">insert into user_info (user_name,password,delete_flag) values (#{userName},#{password},#{deleteFlag})</insert>
@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testvoid insertUserInfo() {UserInfo userInfo = new UserInfo();userInfo.setUserName("yaoyu");userInfo.setPassword("12412");userInfo.setDeleteFlag(0);userMapper.insertUserInfo(userInfo);}
}
?寫測試類,測試通過,看看效果:
增添成功了;?
2,刪
把剛才添加的字段刪了:
?
void deleteUserInfoById(Integer id);
<delete id="deleteUserInfoById">delete from user_info where id = #{id}</delete>
@Testvoid deleteUserInfoById() {userMapper.deleteUserInfoById(11);}
?刪除成功了。
3,查
UserInfo selectUserInfoBYId(Integer id);
<select id="selectUserInfoBYId" resultType="org.example.java_test_6_7.model.UserInfo">select * from user_info where id = #{id}</select>
@Testvoid selectUserInfoBYId() {UserInfo userInfo = userMapper.selectUserInfoBYId(1);System.out.println(userInfo);}
成功查詢并拿到值了;?
4,改
void updateUserInfoById(UserInfo userInfo);
<update id="updateUserInfoById">update user_info set user_name=#{userName}, password=#{password} ,delete_flag=#{deleteFlag} where id =#{id}</update>
@Testvoid updateUserInfoById() {UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setUserName("姚宇");userInfo.setPassword("3141");userInfo.setDeleteFlag(0);userMapper.updateUserInfoById(userInfo);}
OK了?
5,java和數據庫參數名對應不上
還是那三個方法
1,使用as
2,結果映射
3,駝峰自動轉換
1和3跟注解是一模一樣的就不講了,這里我們講結果映射:
UserInfo selectUserInfoBYId2(Integer id);
<resultMap id="base" type="org.example.java_test_6_7.model.UserInfo"><result column="delete_flag" property="deleteFlag"></result><result column="user_name" property="userName"></result><result column="create_time" property="createTime"></result><result column="update_time" property="updateTime"></result></resultMap>
@Testvoid selectUserInfoBYId2() {UserInfo userInfo = userMapper.selectUserInfoBYId2(1);System.out.println(userInfo);}
?看結果:
OK的,這里我已經把駝峰自動轉換關掉了;?
3,多表查詢
再來一個表,我們來弄model?;
@Data
public class BookInfo {private Integer id;private String bookName;private String author;private Integer count;private BigDecimal price;private String publish;private Integer status;private Date createTime;private Date updateTime;
}
來寫一個多表查詢語句?
SELECT bo.id, bo.book_name, bo.author, uo.user_name, uo.`password` FROM user_info uo LEFT JOIN book_info bo ON bo.id = uo.id WHERE bo.id = 1
?
結果,那我們該怎么接收它呢,我們只需要再創建一個對象,對應這個字段的屬性就好了;
@Data
public class Testselect {private Integer id;private String bookName;private String author;private String userName;private String password;
}
@Select("SELECT bo.id, bo.book_name, bo.author, uo.user_name, uo.`password` FROM user_info uo LEFT JOIN book_info bo ON bo.id = uo.id WHERE bo.id = #{id}")TestSelect selectUserInfoAndBookInfoById(Integer id);
@Testvoid selectUserInfoAndBookInfoById() {TestSelect testSelect = userMapper.selectUserInfoAndBookInfoById(1);System.out.println(testSelect);}
?
?成功查到了
4,#{}和${}的區別
現在來正式講一下$和#,
看一下#號的,這個?id后面是一個?下面表示它要填寫的值,這個是預編譯SQL用?來站位
看下用${}的:
@Select("select * from user_info where id = ${id}")UserInfo selectUserInfoById3(Integer id);
void selectUserInfoById3() {UserInfo userInfo = userMapper.selectUserInfoById3(1);System.out.println(userInfo);}
看到是沒有任何占位符的,這個是即時SQL,
@Select("select * from user_info where user_name = ${userName}")UserInfo selectUserInfoById4(String userName);
?來看看這個字符串的
@Testvoid testSelectUserInfoById4() {UserInfo userInfo = userMapper.selectUserInfoById4("姚宇");System.out.println(userInfo);}
發現報錯了啊,?這說明是SQL語句出現了問題的,這個是因為是直接拼接的,沒有引號,正常字符串是需要加引號的,
@Select("select * from user_info where user_name = '${userName}'")UserInfo selectUserInfoById4(String userName);
?
這下就通過了;?
我們來具體說說區別:
主要區別就是即時SQL和預編譯SQL的區別;
即時SQL呢,首先解析語法和語句,檢驗SQL是否正確,優化SQL語句,指定執行計劃,之后執行返回結果;
1. 性能更? 絕?多數情況下,某?條SQL語句可能會被反復調?執?,或者每次執?的時候只有個別的值不同(? 如select的where?句值不同,update的set?句值不同,insert的values值不同).如果每次都需要 經過上?的語法解析,SQL優化、SQL編譯等,則效率就明顯不?了.
預編譯SQL,編譯?次之后會將編譯后的SQL語句緩存起來,后?再次執?這條語句時,不會再次編譯 (只是輸?的參數不同),省去了解析優化等過程,以此來提?效率
1. 更安全(防?SQL注?) SQL注?:是通過操作輸?的數據來修改事先定義好的SQL語句,以達到執?代碼對服務器進?攻擊的 ?法。?
這個SQL注入是很嚴重的,那我們還有使用$的必要了嗎,當然是有的,我們可以自己處理來預防SQ注入,還有一些功能是需要使用$而#是用不了的
1,排序
@Select("select * from book_info order by id ${sort}")List<BookInfo> selectBooInfoOrderById(String sort);
@Testvoid selectBooInfoOrderById() {userMapper.selectBooInfoOrderById("DESC");}
查到了;
為啥只能用$呢,因為sql中這個DESC是不加''號的,但是使用#的話會把我們傳入的字符串自動加引號,但是sql語法是不對的;
2,like
@Select("select * from book_info where book_name like concat('%','${key}','%')")List<BookInfo> selectBooInfoLike(String key);
@Testvoid selectBooInfoLike() {userMapper.selectBooInfoLike("");}
?
?