MyBatis--單表的CURD操作(原始dao方式)

MyBatis--單表的CURD操作(原始dao方式)

CURD操作,即指對數據庫中實體對象的增create、改Update、查Read、刪Delete操作

一、自定義Dao接口實現類

搭建環境

Dao接口:

public interface IStudentDao {
    //插入
    void insertStudent(Student student);
    void insertStudentCacheId(Student student);
    //刪改
    void deleteStudentById(int id);
    void updateStudent(Student student);
    //查詢所有
    List<Student> selectAllStudents();
    Map<String, Object> selectAllStudentsMap();
    //查詢指定學生
    Student selectStudentById(int id);
    Student selectStudentByMap(Map<String, Object> map);
    //根據姓名查詢
    List<Student> selectStudentsByName(String name);
}

Dao實現類:

public class StudentDaoImpl implements IStudentDao {

    private SqlSession sqlSession;

    @Override
    public void insertStudent(Student student) {
        
        try {
        
            sqlSession = MyBatisUtils.getSqlSession();
            sqlSession.insert("insertStudent",student);
            sqlSession.commit();
        } finally{
            if(sqlSession!=null){
                sqlSession.close();
            }
        }   
    }
}

測試:

public class MyTest {
    
    private IStudentDao dao;
    
    @Before
    public void before(){
        dao = new StudentDaoImpl();
    }
}

1.單純插入數據

映射文件:

<insert id="insertStudent" parameterType="com.hcx.beans.Student">
        insert into 
        student(name,age,score) 
        values(#{name},#{age},#{score})
</insert>
  • id:該sql語句的唯一標識,java代碼中要使用該標識。
  • "#{}":對指定參數類型屬性值的引用。其底層是通過反射機制,調用student類相關屬相的get方法來獲取值得。因為底層使用的是反射,所以這里使用的是類的屬性名,而非表的字段名。

dao實現類:

@Override
public void insertStudent(Student student) {
    
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        sqlSession.insert("insertStudent",student);
        sqlSession.commit();
    } finally{
        if(sqlSession!=null){
            sqlSession.close();
        }
    }   
}

注意:執行完對DB的修改操作,必須要做Sqlsession的提交。否則,修改將無法同步到DB中。因為使用無參的openSession()方法已經將事務自動提交功能給關閉了。

測試類:

@Test
public void test01(){       
    Student student = new Student("張三",23,99.8);
    dao.insertStudent(student);
}

2.插入后用新id初始化被插入對象

mysql中在插入語句后執行如下語句,則會輸出新插入記錄的id

insert into student(name,age,score) values('王五',25,95.5);
select @@identity;

映射文件中的<insert/>標簽中,有一個子標簽<selectKey/>用于獲取新插入記錄的主鍵值。

1.以下兩種寫法均可以完成“使用新插入記錄的主鍵值初始化被插入的對象”的功能:

方式一:

<insert id="insertStudentCatchId" parameterType="com.hcx.beans.Student">
    insert into student(name,age,score) 
    values(#{name},#{age},#{score})
    <selectKey resultType="int" keyProperty="id" order="AFTER">
        select @@identity
    </selectKey>
</insert>

方式二:

<insert id="insertStudentCatchId2" parameterType="com.hcx.beans.Student">
    insert into student(name,age,score) 
    values(#{name},#{age},#{score})
    <selectKey resultType="int" keyProperty="id" order="AFTER">
        select last_insert_id();
    </selectKey>
</insert>
  • resultType:指出獲取的主鍵的類型
  • keyProperty:指出主鍵在java類中對應的屬性名。此處會將獲取的主鍵值直接封裝到被插入的student對象中,即dao中insert()方法的第二個參數對象中。
  • order:指出id的生成相對于insert語句的執行是在前還是在后。MySql數據庫表中的id,均是先執行insert語句,而后生成id,所以需要設置為after;oracle數據庫表中的id,則是在insert執行之前先生成,所以需要設置為before。當前的MyBatis版本,不指定order屬性,則會根據所用DBMS,自動選擇其值。

2.Dao實現類

@Override
public void insertStudentCacheId(Student student) {
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        sqlSession.insert("insesrtStudentCatchId",student);
        sqlSession.commit();
    }finally{
        if(sqlSession != null) {
            sqlSession.close();
        }               
    }
}

3.測試類:

//插入后用新id初始化被插入對象
@Test
public void test02(){
    Student student = new Student("張三",23,99.8);
    System.out.println("插入前student="+student);
    dao.insertStudentCatchId(student);
    System.out.println("插入后student="+student);
}

3.刪除數據

1.映射文件:

<delete id="deleteStudentById">
    delete from student where id=#{id}
</delete>

注意:這里的動態參數id所賦值為#{id}。這個#{}表示這就是個占位符,代表delete()方法的第二個參數。#{}中可以放任意值,無需要與delete方法的第二個參數值相同。

2.dao實現類

@Override
public void deleteStudentById(int id) {
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        sqlSession.insert("deleteStudentById",id);
        sqlSession.commit();
    }finally{
        if(sqlSession != null) {
            sqlSession.close();
        }               
    }       
}

3.測試類

@Test
public void test03(){
    dao.deleteStudentById(3);       
}

4.修改數據

1.映射文件:

<update id="updateStudnet">
    update student 
    set name=#{name},age=#{age},score=#{score}
    where id=#{id}
</update>

注意,這里的#{}中,必須要填寫update()方法所傳第二個參數student對象的屬性名稱,不能隨意填寫。

2.dao實現類

@Override
public void updateStudent(Student student) {
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        sqlSession.update("updateStudnet",student);
        sqlSession.commit();
    }finally{
        if(sqlSession != null) {
            sqlSession.close();
        }               
    }       
}

3.測試類

@Test
public void test04(){
    Student student = new Student("得的",26,96.6);
    student.setId(5);
    dao.updateStudent(student);
    
}

5.查詢所有對象-返回list

1.映射文件

<select id="selectAllStudents" resultType="com.hcx.beans.Student">
    select * from student
</select>

注意,resultType屬性并非指查詢結果最后的類型,而是每查出DB中的一條記錄,將該記錄封裝成為的對象的類型。

2.dao實現類

完成dao實現類的selectAllStudent()方法。使用Sqlsession的selectList()方法完成查詢操作。該方法會將查詢出的每條記錄封裝為指定類型對象后,再將最后的結果集封裝為list返回。

方法原型為:List selectList(String statement)
statement:映射文件中配置的SQL語句的id。

@Override
public List<Student> selectAllStudents() {
    List<Student> students = null;
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        students = sqlSession.selectList("selectAllStudents");
        //sqlSession.commit();
    }finally{
        if(sqlSession != null) {
            sqlSession.close();
        }               
    }
    return students;
}

注意:在寫查詢時,由于不是對DB中的數據進行修改,所以無需進行Sqlsession的提交。但最終Sqlsession對象還是需要關閉的。

3.測試類

@Test
public void test05(){
    List<Student> students = dao.selectAllStudents();
    for (Student student : students) {
        System.out.println(student);
    }       
}

6.查詢所有對象-返回Map

1.映射文件

<select id="selectAllStudents" resultType="com.hcx.beans.Student">
    select * from student
</select>

2.dao實現類

完成dao實現類的selectStudentMap()方法。使用Sqlsession的selectMap()方法完成查詢操作。該查詢方法會將查詢出的每條記錄先封裝為指定對象,然后再將該對象作為value,將該對象的指定屬性所對應的字段名作為key封裝為一個map對象。

方法原型:Map<Object,Object> selectMap(String statement,String mapKey)

  • statement:映射文件中配置的sql語句的id
  • mapkey:查詢出的map所要使用的key。這個key為數據表的字段名。查詢出的結果是一個map,每行記錄將會對應一個Map.entry對象,該對象的key為指定字段的值,value為記錄數據所封裝的對象

代碼:

@Override
public Map<String, Object> selectAllStudentsMap() {
    Map<String, Student> studentsMap = null;
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        studentsMap = sqlSession.selectMap("selectAllStudents", "name"); //name:指定所形成map的key
    } finally{
        if(sqlSession!=null){
            sqlSession.close();
        }
    }
    return null;
}

3.測試類

@Test
public void test06(){
    Map<String, Student> map = dao.selectAllStudentsMap();
    Student student = map.get("張三");
    System.out.println(student);
}

注意:若指定的作為key的屬性值在DB中并不唯一,則后面的記錄值會覆蓋掉前面的值。即指定key的value值,一定是DB中該同名屬性的最后一條記錄值。

7.查詢單個對象

1.映射文件

<select id="selectStudnetById" resultType="com.hcx.beans.Student">
    select * from student where id=#{id}
</select>

2.dao實現類

使用Sqlsession的selectOne()方法。其會將查詢的結果記錄封裝為一個指定類型的對象。

方法原型:Object selectOne(String statement,Object parameter)

  • statement:映射文件中配置的SQL語句的id
  • parameter:查詢條件中動態參數的值

代碼:

@Override
public Student selectStudentById(int id) {
    Student student = null;
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        student = sqlSession.selectOne("selectStudentById",id);
        sqlSession.commit();
    }finally{
        if(sqlSession != null) {
            sqlSession.close();
        }               
    }
    return student;
}

3.測試類

@Test
public void test07(){
    Student student = dao.selectStudentById(3);
    System.out.println(student);
}

8.模糊查詢

1.映射文件

寫法一:

<select id="selectStudnetByName" resultType="com.hcx.beans.Student">
    select * from student 
    where name like concat('%',#{name},'%')
</select>

在進行模糊查詢時,需要進行字符串的拼接。sql中的字符串的拼接使用的是函數concat(arg1,arg2,...)。注意不能使用java中的字符串連接符+。

寫法二:

<select id="selectStudnetByName" resultType="com.hcx.beans.Student">
    select * from student 
    where name like '%' #{name} '%'
</select>

以上兩種形式是等效的。都是以動態參數的形式出現在sql語句中的。

寫法三:
還可使用如下方式,需要注意,只能使用${}中只能使用value,不能使用其他:

<select id="selectStudnetByName" resultType="com.hcx.beans.Student">
    select * from student 
    where name like '%${value}%'
</select>

這種方式是純粹的字符串拼接,直接將參數拼接到了sql語句中,所以可能會發生sql注入

2.dao實現類

@Override
public List<Student> selectStudentsByName(String name) {
    List<Student> students = null;
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        students = sqlSession.selectOne("selectStudentByName",name);
        sqlSession.commit();
    }finally{
        if(sqlSession != null) {
            sqlSession.close();
        }               
    }
    return students;
}

3.測試類

@Test
public void test08(){
    List<Student> students = dao.selectStudentsByName("張");
    for (Student student : students) {
        System.out.println(student);
    }
}

$與#的區別:

#為占位符,$為字符串拼接符
字符串拼接是將參數值以硬編碼的方式直接拼接到了sql語句中。
字符串拼接就會引發兩個問題:
sql注入問題與沒有使用預編譯所導致的執行效率低下問題

應用場景:

一般情況下,動態參數的值是由用戶輸入的,則不能使用拼接符$,因為有可能會出現sql注入;若動態參數的值是由系統計算生成的,則可以使用拼接符$。但這樣雖然不存在sql注入的風險,但仍存在執行效率問題。

9.根據map進行查詢

mapper中sql語句的動態參數也可以是map的key

1.測試類

map中存放兩個“鍵-值”對,即有兩個key

@Test
public void test09(){
    Student student = new Student();
    student.setId(5);
    
    Map<String, Object> map = new HashMap<String,Object>();
    map.put("studentId", 2);
    map.put("student", student);
    
    student = dao.selectStudentByMap(map);
    System.out.println(student);
    
}

2.映射文件

<select id="selectStudentByMap" resultType="com.hcx.beans.Student">
    select * from student 
    where id=#{studentId}
</select>

<select id="selectStudentByMap2" resultType="com.hcx.beans.Student">
    select * from student 
    where id=#{student.id}
</select>

3.dao實現類

@Override
public Student selectStudentByMap(Map<String, Object> map) {
    Student student = null;
    try {
        sqlSession = MyBatisUtils.getSqlSession();
        student = sqlSession.selectOne("selectStudentByMap",map);
        sqlSession.commit();
    }finally{
        if(sqlSession != null) {
            sqlSession.close();
        }               
    }
    return student;
}

二、屬性名與查詢字段名不相同

resultType可以將查詢結果直接映射為實體Bean對象的條件是,sql查詢的字段名與實體Bean的屬性名一致。因為在將查詢結果轉換為指定類型對象時,系統自動將查詢結果字段名稱作為對象的屬性名,通過反射機制完成對象的創建。

當sql查詢結果的字段名和實體Bean的屬性名不一致時,將無法創建出需要類型的對象。此時有兩種解決方案:查詢字段使用別名或使用結果映射resultMap

1.修改student表

student表.PNG

2.dao接口

public interface IStudentDao {
    Student selectStudentById(int id);
}

3.測試類

public class MyTest {
    
    @Test
    public void test1(){
        IStudentDao dao = new StudentDaoImpl();
        Student student = dao.selectStudentById(3);
        System.out.println(student);
    }
}

4.dao實現類

public class StudentDaoImpl implements IStudentDao {

    @Override
    public Student selectStudentById(int id) {
        SqlSession sqlSession = null;
        Student student = null;
        try {
            sqlSession = MyBatisUtils.getSqlSession();
            student = sqlSession.selectOne("selectById2",id);
        } finally{
            if(sqlSession!=null){
                sqlSession.close();
            }
        }   
    }
}

解決方式一:查詢字段使用別名

雖然屬性名稱與表中的字段名稱不一樣,但可以為查詢結果的字段名稱賦予別名,讓別名與實體Bean的屬性相同。這樣框架也可以根據查詢結果利用反射機制將對象創建。

在映射文件mapper中添加如下映射。注意,由于表的score字段名與student類的屬性名相同,所以這里無需使用別名。

<select id="selectStudentById" resultType="Student">
    select tid id,tname name,tage,age,score
    from student where tid=#{tid}
</select>

解決方式二:使用結果映射resultMap

可以使用結果映射resultMap來建立映射關系,完成由字段到屬性的映射,達到將查詢結果封裝為對象的目的。resultMap是對resultType的增強。

<resultMap type="Student" id="studentMapper">
    <id column="tid" property="id"/>
    <result column="tname" property="name"/>
    <result column="tage" property="age"/>
</resultMap>

<select id="selectStudentById" resultMap="studentMapper">
    select tid, tname, tage, score
    from student where tid=#{tid}
</select>

<resultMap/>標簽中定義了由type指定的類的屬性名到表中字段名稱的映射關系。根據這個映射關系,框架利用反射機制創建相應對象。

  • type:指定要映射的實體類
  • id:指定該resultMap映射關系的名稱
  • <id>標簽:id的字段名column與實體類的屬性property間的映射關系
  • <result>標簽:id以外其他字段名column與實體類的屬性property間的映射關系

如果字段名與實體類的屬性名相同的情況,可以不寫入<resultMap/>中。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內容