mybatis筆記整理

前言:

mybatis可以說(shuō)是最容易上手的持久層框架了,相比于hibernate 而言,它都是直接用sql語(yǔ)句對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,而不是用hql,尤其是關(guān)聯(lián)關(guān)系復(fù)雜的時(shí)候,mybatis更容易實(shí)現(xiàn)。下面是本人學(xué)習(xí)過(guò)程的一些筆記。
本文涉及知識(shí)點(diǎn):
1、mybatis入門(mén)
2、配置版CRUD
3、關(guān)聯(lián)查詢(1:1&1:n)
4、mybatis 的注解形式
5、sql語(yǔ)句構(gòu)建器版CRUD
6、動(dòng)態(tài)sql的應(yīng)用


歡迎大家關(guān)注我的公眾號(hào) javawebkf,目前正在慢慢地將簡(jiǎn)書(shū)文章搬到公眾號(hào),以后簡(jiǎn)書(shū)和公眾號(hào)文章將同步更新,且簡(jiǎn)書(shū)上的付費(fèi)文章在公眾號(hào)上將免費(fèi)。


一、mybatis入門(mén)

1、引入相關(guān)的依賴:
這里不作介紹,可以參考ssm整的所需依賴

2、關(guān)于mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
      <configuration>
       <!-- 引入jdbc.properties配置文件,獲取連接數(shù)據(jù)庫(kù)信息,推薦 -->
    <properties resource="jdbc.properties"/>
    
    <!-- 連接數(shù)據(jù)庫(kù)信息也可以直接寫(xiě)這里,如以下寫(xiě)法,不推薦 -->
    <!-- <properties>       <property name="jdbc.driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="jdbc.url" value="jdbc:mysql://localhost:3306/db_mybatis"/>
        <property name="jdbc.username" value="root"/>
        <property name="jdbc.password" value="123456"/>
    </properties> -->
    
    
    
    <!-- 取別名,在StudentMapper.xml的parameterType屬性中就不用寫(xiě)全類名 -->
    
    <!-- 方式一,不推薦 -->
    <!-- <typeAliases>
        <typeAlias alias="Student" type="com.java1234.model.Student"/>
    </typeAliases> -->
    
    <!-- 方式二,推薦,掃描此包下所有實(shí)體 -->
    <typeAliases>
        <package name="com.zhu.entity"/>
    </typeAliases>
    
    
    <!-- 配置環(huán)境 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
        
        
        <environment id="test">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}" />
                <property name="url" value="${jdbc.url}" />
                <property name="username" value="${jdbc.username}" />
                <property name="password" value="${jdbc.password}" />
            </dataSource>
        </environment>
    </environments>
    
    
    <!-- 讀取映射文件 -->
    <mappers>
    
        <!-- <mapper resource="com/zhu/mappers/StudentMapper.xml" /> 不推薦-->
        <!-- <mapper class="com.zhu.mappers.StudentMapper"/> 不推薦-->
        <!-- 推薦,掃描此包下所有映射文件 -->
        <package name="com.zhu.mappers"/>
    </mappers>
</configuration>

以上大部分配置在做ssm整合時(shí)都會(huì)寫(xiě)在spring 配置文件中,這里只是讓大家了解一下。
3、dao層以及實(shí)現(xiàn):

public interface StudentMapper {
      public int add(Student student);
       }

StudentMapper.xml:

<mapper namespace="com.zhu.mappers.StudentMapper">
 <insert id="add" parameterType="Student">
         insert into t_student 
         values(null,#{name},#{age})
</insert>
</mapper> 

再來(lái)個(gè)獲取sqlSessionFactory的工具類:

public class SqlSessionFactoryUtil {
    private static SqlSessionFactory
               sqlSessionFactory;   
    public static SqlSessionFactory 
               getSqlSessionFactory(){
               if(sqlSessionFactory==null){
        
InputStream inputStream=null;
    try{                             inputStream    =    Resources
.getResourceAsStream("mybatisconfig.xml");
sqlSessionFactory=new 
SqlSessionFactoryBuilder().build(inputStream);
    }catch(Exception e){
        e.printStackTrace();
        }
             }
         return sqlSessionFactory;
             }  
          public static SqlSession openSession(){
        return getSqlSessionFactory()
                .openSession();
          }
            }

4、測(cè)試:

public static void main(String[] args) {
        SqlSession sqlSession=SqlSessionFactoryUtil.openSession();
        StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);
        Student student=new Student("李四",11);
        int result=studentMapper.add(student);
  sqlSession.commit();

二、配置版CRUD:

1、dao接口定義CRUD方法:

public interface StudentMapper {

    public int add(Student student);
    
    public int update(Student student);
    
    public int delete(Integer id);
    
    public Student findById(Integer id);
    
    public List<Student> find();
      }

2、StudentMapper.xml:
增加方法,id是接口中對(duì)應(yīng)的方法名,parameterType就是方法的參數(shù)類型,因?yàn)樵趍ybatis-config配置文件中配置了typeAliases,所以這里可以直接寫(xiě)Student,否則就要寫(xiě)全類名。
mybatis用 #{屬性名} 獲取實(shí)體類的屬性值。

<insert id="add" parameterType="Student"  >
   insert into t_student 
   values(null,#{name},#{age})
</insert>

更新方法:

<update id="update" parameterType=
      "Student">
     update t_student 
     set name=#{name},age=#{age} 
     where id=#{id}
</update>

刪除方法:

<delete id="delete" parameterType="Integer">
        delete from t_student 
        where id=#{id}
</delete>

根據(jù)id查學(xué)生(1個(gè)):resultType是參數(shù)類型

<select id="findById" parameterType=
        "Integer" resultType="Student">
    select * from t_student 
        where id=#{id}
</select>

查詢所有學(xué)生:可以先定義一個(gè)resultMap來(lái)接收返回的學(xué)生。

<resultMap type="Student"
                                 id="StudentResult">
    <id property="id" column="id"/>
        <result property="name" 
                     column="name"/>
        <result property="age"
                     column="age"/>
</resultMap>

在這里引用剛才定義的resultMap:

<select id="find" resultMap=
                          "StudentResult">
    select * from t_student
</select>

注意:
這里說(shuō)一說(shuō)resultType和resultMap,其實(shí)剛才那個(gè)方法也可以用resultType,如果查詢結(jié)果字段與實(shí)體類字段名稱完全一致,可以不映射;resultMap只有在select中才會(huì)用到。有三種情況會(huì)用到ResultMap:
1、如果查詢結(jié)果字段與實(shí)體類的字段名稱不對(duì)應(yīng);
2、查詢結(jié)果的字段類型與實(shí)體類的字段類型不一致;
3、查詢結(jié)果對(duì)應(yīng)多個(gè)實(shí)體類(多表關(guān)聯(lián)查詢時(shí))。

三、多表關(guān)聯(lián)查詢問(wèn)題

1、一對(duì)一關(guān)聯(lián):
給student類增加一個(gè)address屬性,一個(gè)學(xué)生對(duì)應(yīng)一個(gè)地址

public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Address address;
}
public class Address {

    private Integer id;
    private String sheng;
    private String shi;
    private String qu;
}

根據(jù)student的id查詢學(xué)生,查詢結(jié)果帶有地址信息

public interface StudentMapper {
    public Student
        findStudentWithAddress(Integer id);
}

AddressMapper.xml


<select id="findById" parameterType="Integer" resultType="Address">
        select * from t_address 
                where id=#{id}
</select>

StudentMapper.xml:
因?yàn)閟tudent新增了一個(gè)Address類型的屬性,查詢結(jié)果對(duì)應(yīng)了student和Address兩個(gè)類,屬于復(fù)合類型,因此要定義resultMap來(lái)接收。

<resultMap type="Student" id="StudentResult">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
                <--property表示實(shí)體類中的屬性名,column是數(shù)據(jù)庫(kù)中對(duì)應(yīng)的字段名-->
<association property="address"                   column="addressId"
   select="com.zhu.mappers
 .AddressMapper.findById">
 </association>
</resultMap>

然后在select標(biāo)簽中引用這個(gè)resultMap:

<select id="findStudentWithAddress" resultMap="StudentResult" parameterType="Integer">
          select * from t_student t1,t_address t2
where t1.addressId=t2.id 
and t1.id=#{id}
</select>

2、一對(duì)多關(guān)聯(lián):
一對(duì)多,多個(gè)學(xué)生屬于一個(gè)年級(jí),即學(xué)生為n,年級(jí)為1

public interface StudentMapper {
    public Student findByGradeId(Integer gradeId);
}

StudentMapper.xml:

<resultMap type="Student" id="StudentResult">
        <id property="id" column="id"/>     <result property="name" column="name"/>
    <result property="age" column="age"/>
                 <!--property="grade"表示學(xué)生的grade屬性,column="gradeId"表示外鍵,select指查詢年級(jí)方法的全類名-->
        <association property="grade" column="gradeId" select="com.zhu.mappers.GradeMapper.findById"></association>
    </resultMap>
        <select id="findByGradeId" resultMap="StudentResult" parameterType="Integer">
    select * from t_student 
        where gradeId=#{gradeId}
</select>
public interface GradeMapper {
    public Grade findById(Integer id);
}

GradeMapper.xml:

<resultMap type="Grade" id="GradeResult">
        <result property="id" column="id"/>
    <result property="gradeName" column="gradeName"/>
                <!--property="students"表示grade的student屬性,column="id",此ID是學(xué)生ID-->
        <collection property="students" column="id" select="com.zhu.mappers.StudentMapper.findByGradeId"></collection>
</resultMap>
    
 <select id="findById" parameterType="Integer" resultMap="GradeResult">
        select * from t_grade 
                where id=#{id}
</select>

關(guān)于一對(duì)一以及一對(duì)多關(guān)聯(lián)查詢?cè)斀?,?qǐng)參見(jiàn)mybatis關(guān)聯(lián)查詢之a(chǎn)ssociation和collection

四、mybatis的注解形式

mybatis也可以把sql語(yǔ)句直接把注解形式寫(xiě)在dao層的接口方法上:
1、注解版CRUD:

@Insert("insert into t_student values(null,#{name},#{age})")
    public int insertStudent(Student student);

    
    @Update("update t_student set name=#{name},age=#{age} where id=#{id}")
    public int updateStudent(Student student);


    
    @Delete("delete from t_student where id=#{id}")
    public int deleteStudent(int id);


    
    @Select("select * from t_student where id=#{id}")
    public Student getStudentById(Integer id);
    



    @Select("select * from t_student")
    @Results(
            {
                @Result(id=true,column="id",property="id"),
                @Result(column="name",property="name"),
                @Result(column="age",property="age")
            }
    )
    public List<Student> findStudents();

2、注解版關(guān)聯(lián)查詢:

①、一對(duì)一關(guān)聯(lián)查詢:
studentMapper.java

 @Select("select * from t_student where gradeId=#{gradeId}")
    @Results(
            {
                @Result(id=true,column="id",property="id"),
                @Result(column="name",property="name"),
                @Result(column="age",property="age"),
                @Result(column="addressId",property="address",one=@One(select="com.zhu.mappers.AddressMapper.findById"))
            }
    )
    public Student selectStudentByGradeId(int gradeId);

gradeMapper.java

public interface GradeMapper {

    @Select("select * from t_grade where id=#{id}")
    @Results(
            {
                @Result(id=true,column="id",property="id"),
                @Result(column="gradeName",property="gradeName"),
                @Result(column="id",property="students",many=@Many(select="com.java1234.mappers.StudentMapper.selectStudentByGradeId"))
            }
    )
    public Grade findById(Integer id);

}

②、一對(duì)一和一對(duì)多:

@Select("select * from t_student where id=#{id}")
    @Results(
            {
                @Result(id=true,column="id",property="id"),
                @Result(column="name",property="name"),
                @Result(column="age",property="age"),
                @Result(column="addressId",property="address",one=@One(select="com.zhu.mappers.AddressMapper.findById")),
                @Result(column="gradeId",property="grade",one=@One(select="com.zhu.mappers.GradeMapper.findById"))
            }
    )
    public Student selectStudentWithAddressAndGrade(int id);

五、sql語(yǔ)句構(gòu)建器版CRUD:

sql語(yǔ)句構(gòu)建器,就是把sql語(yǔ)句寫(xiě)在一個(gè)類中,然后在接口方法上引用這個(gè)類,請(qǐng)看下面的代碼:
1、構(gòu)建器類:

public class StudentDynaSqlProvider {

    public String insertStudent(final Student student){
        return new SQL(){
            {
                INSERT_INTO("t_student");
                if(student.getName()!=null){
                    VALUES("name", "#{name}");
                }
                if(student.getAge()!=null){
                    VALUES("age", "#{age}");
                }
            }
        }.toString();
    }
    
    public String updateStudent(final Student student){
        return new SQL(){
            {
                UPDATE("t_student");
                if(student.getName()!=null){
                    SET("name=#{name}");
                }
                if(student.getAge()!=null){
                    SET("age=#{age}");
                }
                WHERE("id=#{id}");
            }
        }.toString();
    }
    
    public String deleteStudent(){
        return new SQL(){
            {
                DELETE_FROM("t_student");
                WHERE("id=#{id}");
            }
        }.toString();
    }
    
    public String getStudentById(){
        return new SQL(){
            {
                SELECT("*");
                FROM("t_student");
                WHERE("id=#{id}");
            }
        }.toString();
    }
    
    public String findStudents(final Map<String,Object> map){
        return new SQL(){
            {
                SELECT("*");
                FROM("t_student");
                StringBuffer sb=new StringBuffer();
                if(map.get("name")!=null){
                    sb.append(" and name like '"+map.get("name")+"'");
                }
                if(map.get("age")!=null){
                    sb.append(" and age="+map.get("age"));
                }
                if(!sb.toString().equals("")){
                    WHERE(sb.toString().replaceFirst("and", ""));                   
                }
            }
        }.toString();
    }
}

2、在接口方法上引用:

public interface StudentMapper {

    @InsertProvider(type=StudentDynaSqlProvider.class,method="insertStudent")
    public int insertStudent(Student student);
    
    @UpdateProvider(type=StudentDynaSqlProvider.class,method="updateStudent")
    public int updateStudent(Student student);
    
    @DeleteProvider(type=StudentDynaSqlProvider.class,method="deleteStudent")
    public int deleteStudent(int id);
    
    @SelectProvider(type=StudentDynaSqlProvider.class,method="getStudentById")
    public Student getStudentById(Integer id);
    
    @SelectProvider(type=StudentDynaSqlProvider.class,method="findStudents")
    public List<Student> findStudents(Map<String,Object> map);
    
}

3、junit測(cè)試:


@Test
    public void testInsert() {
        Student student=new Student("琪琪",11);
        studentMapper.insertStudent(student);
        sqlSession.commit();
    }

六、動(dòng)態(tài)sql的應(yīng)用:

1、mybatis帶條件分頁(yè)查詢
mybatis分頁(yè)并不難,只要傳入rowIndex和pageSize,然后用limit語(yǔ)句即可;關(guān)于帶條件查詢,要查哪個(gè)對(duì)象就把條件封裝成那個(gè)對(duì)象的一個(gè)實(shí)體,然后在xml中通過(guò)where標(biāo)簽解析出來(lái)即可。話不多說(shuō),看如下代碼:
User.java

public class User {
    private Integer userId;
    private String userName;
    private Integer age;
    private Card card;//一個(gè)人一張身份證,1對(duì)1
    private List<MobilePhone> mobilePhone;//土豪,多個(gè)手機(jī),1對(duì)多
}

Card.java

public class Card {
    private Integer cardId;
    private String cardNum;//身份證號(hào)
    private String address;//地址
}

MobilePhone.java

private Integer mobilePhoneId;
    private String brand;//品牌
    private double price;//價(jià)格
    private User user;//主人
}

UserDao.java

/**
     * 帶條件分頁(yè)查詢:
     *     可輸入的條件:名字(模糊),cardId,age,
     * @param userCondition 把條件封裝成一個(gè)user對(duì)象
     * @param rowIndex 表示從第幾行開(kāi)始取數(shù)據(jù)
     * @param pageSize 表示要返回多少行數(shù)據(jù)
     * @return 返回user列表
     */
    List<User> queryUserList(@Param("userCondition") User userCondition, @Param("rowIndex") int rowIndex,
        @Param("pageSize") int pageSize);

UserDao.xml

<!--定義resultMap-->
<resultMap type="User" id="userMap">
          <id property="userId" column="user_id"/>
          <result property="userName" column="user_name"/>
          <result property="age" column="age"/>
          <association property="card" column="card_id" javaType="Card">
            <id property="cardId" column="card_id"/>
            <result property="cardNum" column="card_num"/>
            <result property="address" column="address"/>
          </association>
          <collection property="mobilePhone" column="user_id" ofType="MobilePhone">
            <id column="mobile_phone_id" property="mobilePhoneId" />
            <result column="brand" property="brand" />
            <result column="price" property="price" />
          </collection>
    </resultMap>


<!--帶條件分頁(yè)查詢-->
<select id="queryUserList" resultMap="userMap">
        SELECT
        u.user_name,u.age,u.card_id,c.card_num,c.address,m.brand,m.price
        FROM
        tb_user u,tb_card c,tb_mobile_phone m
        <where>
            <if
                test="userCondition.card != null
                     and 
                    userCondition.card.cardId != null">
                and u.card_id =
                #{userCondition.card.cardId}
            </if>

            <if test="userCondition.userName != null">
                and u.user_name like '%${userCondition.userName}%'
            </if>
            <if test="userCondition.age != null">
                and u.age = #{userCondition.age}
            </if>
            AND
            u.card_id = c.card_id
            AND
            u.user_id = m.user_id
        </where>
        LIMIT #{rowIndex},#{pageSize}
    </select>

junit測(cè)試:

@Test
    public void testQueryUserList() {
        User userCondition = new User();
        /*Card c = new Card();
        c.setCardId(2);
        userCondition.setCard(c);*/
        //userCondition.setAge(22);
        userCondition.setUserName("菲");
        List<User> ul = userDao.queryUserList(userCondition, 1, 99);
        for(User user : ul) {
            System.out.println(user.getUserName());
            /*List<MobilePhone> list = new ArrayList<>();
            list = user.getMobilePhone();
            for(MobilePhone mp : list) {
                System.out.println(mp.getBrand());
            }*/
        }
    }

以上代碼便完成了帶條件分頁(yè)查詢,整個(gè)過(guò)程并不難,只是在select中用了where標(biāo)簽以及用where的子標(biāo)簽if判斷傳入的條件是否為空,不為空就賦值。

2、mybatis的動(dòng)態(tài)更新:
上面CRUD案例中的更新,name和age必須傳入值,沒(méi)有傳入的話那就會(huì)更新成null或0,而這里所說(shuō)的動(dòng)態(tài)更新就是傳了值的才更新,沒(méi)傳值的字段保留原來(lái)的值。看如下案例(實(shí)體類同帶條件分頁(yè)查詢的三個(gè)實(shí)體類):
UserDao.java

int updateUser(User user);

UserDao.xml

<!-- 更新user -->
   <update id="updateUser" parameterType="User">
        UPDATE tb_user
        <set>
            <if test="userName!=null">user_name=#{userName},</if>
            <if test="age!=null">age=#{age},</if>
            <if test="card!=null">card_id=#{card.cardId},</if>
        </set>
        where user_id=#{userId}
   </update>

junit測(cè)試:

@Test
    public void testUpdateUser() {
        User user = new User();
        user.setUserId(4);
        user.setAge(22);
        Card c = new Card();
        c.setCardId(1);
        user.setCard(c);
        int result = userDao.updateUser(user);
        assertEquals(1, result);
    }

動(dòng)態(tài)更新就是在select標(biāo)簽中添加了一個(gè)set,然后再用if去判斷傳入的字段是否為空,不為空就更新。

更多動(dòng)態(tài)sql的應(yīng)用,請(qǐng)參考mybatis的動(dòng)態(tài)sql

總結(jié):

mybatis相對(duì)于hibernate來(lái)說(shuō),優(yōu)點(diǎn)在于支持sql語(yǔ)句,而hibernate使用的是hql語(yǔ)句。在業(yè)務(wù)邏輯簡(jiǎn)單不需要編寫(xiě)很多hql語(yǔ)句時(shí)可能使用hibernate更加快捷,因?yàn)樗庋b了一些對(duì)數(shù)據(jù)庫(kù)的基本操作比如save、update等,直接調(diào)用就行;當(dāng)業(yè)務(wù)邏輯比較復(fù)雜,那就選用mybatis更好。

以上內(nèi)容屬于個(gè)人筆記整理,如有錯(cuò)誤,歡迎批評(píng)指正!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥(niǎo)慢飛閱讀 6,248評(píng)論 0 4
  • Java數(shù)據(jù)持久化之mybatis 一. mybatis簡(jiǎn)介 1.1 原始的JDBC操作: Java 通過(guò) Jav...
    小Q逛逛閱讀 5,411評(píng)論 0 16
  • 編寫(xiě)日志輸出環(huán)境配置文件 在開(kāi)發(fā)過(guò)程中,最重要的就是在控制臺(tái)查看程序輸出的日志信息,在這里我們選擇使用 log4j...
    我沒(méi)有三顆心臟閱讀 6,913評(píng)論 0 33
  • 類string的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)和析構(gòu)函數(shù) 引用http://www.cppblog.com/life02/...
    未填寫(xiě)呀閱讀 286評(píng)論 0 0
  • 目標(biāo):2018.3.31前獲得1萬(wàn)元收入支付給同事 1余額寶里給媽媽存入10元,祝媽媽有經(jīng)濟(jì)上的安全感,財(cái)源滾滾開(kāi)...
    平和艷閱讀 101評(píng)論 0 0

友情鏈接更多精彩內(nèi)容