MyBatis第三步、实现数据的增删改查

来源:互联网 发布:电影知无涯者拉马努金 编辑:程序博客网 时间:2024/04/30 18:44
【注意事项】
1、接口的方法名和参数类型要与Mapper文件中的id和parameterType必须保持一致。
2、再用Session进行数据操作时,最后一定要session.commit();,否则没有提交。
3、Mybatis中like的写法 like concat('%',#{param},'%')  或者 like '%${param}%' ,推荐使用前者,可以避免sql注入。



1、查询数据。
当返回的数据是单条记录,可以采用在MyBatis中设置实体类别名的方式,也就是
<select id="selectUsers" parameterType="string" resultMap="User">
如上


但是如果返回的是多条记录,则需要在Mapper文件中配置相应的返回类型resultMap。如下:
    
    <!-- 为了返回list 类型而定义的returnMap -->
    <resultMap type="User" id="resultListUser">
        <id column="id" property="id" />
        <result column="userName" property="userName" />
        <result column="userAge" property="userAge" />
        <result column="userAddress" property="userAddress" />
    </resultMap>
其中,主键采用字段名配置,其他字段采用result方式。column代表SQL语句中的字段名,property代表实体类中的属性名。








【查询语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名(在Mybatis中配置文件中为实体类配置的别名)
resultType:语句返回值类型的整类名或别名。注意,如果是集合,那么这里填写的是集合的项的整类名或别名,而不是集合本身的类名。(resultType 与resultMap 不能并用)
resultMap:引用的外部resultMap 名。结果集映射是MyBatis 中最强大的特性。许多复杂的映射都可以轻松解决。(resultType 与resultMap 不能并用)
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement,preparedstatement,callablestatement。预准备语句、可调用语句
resultSetType:forward_only,scroll_sensitive,scroll_insensitive。只转发,滚动敏感,不区分大小写的滚动






2、增加数据
Mapper中增加语句的写法有两个重要属性,分别是useGeneratedKeys和keyProperty。


useGeneratedKeys是否启用数据库生成的主键。


keyProperty生成的主键赋值的字段是哪个。如下:


<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id"> 
        insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress})  
</insert>
另外还有一种方式,如下:
<insert id="insertStudentAutoKey" parameterType="StudentEntity">  
    <selectKey keyProperty="studentID" resultType="String" order="BEFORE">  
            select nextval('student')  
    </selectKey>  
        INSERT INTO STUDENT_TBL (STUDENT_ID,  
                                 STUDENT_NAME,  
                                 STUDENT_SEX,  
                                 STUDENT_BIRTHDAY,  
                                 CLASS_ID)  
              VALUES   (#{studentID},  
                        #{studentName},  
                        #{studentSex},  
                        #{studentBirthday},  
                        #{classEntity.classID})      
</insert>  




其中 #{userName}代表实体类中的属性名。




【增加语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement、preparedstatement、callablestatement。预准备语句、可调用语句
useGeneratedKeys:告诉MyBatis 使用JDBC 的getGeneratedKeys 方法来获取数据库自己生成的主键(MySQL、SQLSERVER 等关系型数据库会有自动生成的字段)。默认:false
keyProperty:标识一个将要被MyBatis设置进getGeneratedKeys的key 所返回的值,或者为insert 语句使用一个selectKey子元素。


【批量插入】
方法一:
<insert id="add" parameterType="EStudent">
  <foreach collection="list" item="item" index="index" separator=";">
    INSERT INTO TStudent(name,age) VALUES(#{item.name}, #{item.age})
  </foreach>
</insert>
上述方式相当语句逐条INSERT语句执行,将出现如下问题: 
1. mapper接口的add方法返回值将是最后一条INSERT语句的操作成功的记录数目(就是0或1),而不是所有INSERT语句的操作成功的总记录数目 
2. 当其中一条不成功时,不会进行整体回滚。


方法二:
<insert id="insertStudentAutoKey" parameterType="java.util.List">
    INSERT INTO STUDENT_TBL (STUDENT_NAME,  
                                 STUDENT_SEX,  
                                 STUDENT_BIRTHDAY,  
                                 CLASS_ID)  
                              VALUES   
  <foreach collection="list" item="item" index="index" separator=",">
      ( #{item.studentName},#{item.studentSex},#{item.studentBirthday},#{item.classEntity.classID})
  </foreach>
</insert>


3、更新数据,示例如下:
<update id="updateStudent" parameterType="StudentEntity">  
        UPDATE STUDENT_TBL  
            SET STUDENT_TBL.STUDENT_NAME = #{studentName},   
                STUDENT_TBL.STUDENT_SEX = #{studentSex},  
                STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},  
                STUDENT_TBL.CLASS_ID = #{classEntity.classID}  
         WHERE STUDENT_TBL.STUDENT_ID = #{studentID};     
</update>  


【更新语句语法、参数】
id:在这个模式下唯一的标识符,可被其它语句引用
parameterType:传给此语句的参数的完整类名或别名
flushCache:如果设为true,则会在每次语句调用的时候就会清空缓存。select 语句默认设为false
useCache:如果设为true,则语句的结果集将被缓存。select 语句默认设为false
timeout:设置驱动器在抛出异常前等待回应的最长时间,默认为不设值,由驱动器自己决定
fetchSize:设置一个值后,驱动器会在结果集数目达到此数值后,激发返回,默认为不设值,由驱动器自己决定
statementType:statement、preparedstatement、callablestatement。预准备语句、可调用语句


【批量更新】
方法一:(适用于将不同的记录更新不同的值)
<update id="updateBatch"  parameterType="java.util.List">  
    <foreach collection="list" item="item" index="index" open="" close="" separator=";">
        update course
        <set>
            name=${item.name}
        </set>
        where id = ${item.id}
    </foreach>      
</update>
方法二:(适用于将不同记录的更新同样的值)
<update id="updateOrders" parameterType="java.util.List">
     update orders set state = '0' where no in
     <foreach collection="list" item="id" open="(" separator="," close=")">
   #{id}
     </foreach>
</update>




4、删除数据 示例如下:
<delete id="deleteStudent" parameterType="StudentEntity">  
        DELETE FROM STUDENT_TBL WHERE STUDENT_ID = #{studentID}  
</delete> 
 
【批量删除】
<delete id="batchRemoveUserByPks" parameterType="java.util.List">
DELETE FROM LD_USER WHERE ID in 
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
</delete>






5、Sql元素
Sql元素用来定义一个可以复用的SQL 语句段,供其它语句调用。比如:


<!-- 复用sql语句  查询student表所有字段 -->  
<sql id="selectStudentAll">  
        SELECT ST.STUDENT_ID,  
                   ST.STUDENT_NAME,  
                   ST.STUDENT_SEX,  
                   ST.STUDENT_BIRTHDAY,  
                   ST.CLASS_ID  
              FROM STUDENT_TBL ST  
</sql>  


<!-- 查询学生,根据id -->  
<select id="getStudent" parameterType="String" resultMap="studentResultMap">  
    <include refid="selectStudentAll"/>  
            WHERE ST.STUDENT_ID = #{studentID}   
</select> 




6、parameters使用
MyBatis可以使用Java的基本数据类型和Java的复杂数据类型。如:基本数据类型,String,int,date等。
但是使用基本数据类型,只能提供一个参数,所以需要使用Java实体类,或Map类型做参数类型。通过#{}可以直接得到其属性。


【基本类型参数】示例如下:
<select id="getStudentListByDate"  parameterType="Date" resultMap="studentResultMap">  
    SELECT *  
      FROM STUDENT_TBL ST LEFT JOIN CLASS_TBL CT ON ST.CLASS_ID = CT.CLASS_ID  
     WHERE CT.CLASS_YEAR = #{classYear};      
</select> 


【Java实体类型参数】 示例如下:
<select id="getStudentListWhereEntity" parameterType="StudentEntity" resultMap="studentResultMap">  
    SELECT * from STUDENT_TBL ST  
        WHERE ST.STUDENT_NAME LIKE CONCAT('%', #{studentName},'%')  
          AND ST.STUDENT_SEX = #{studentSex}  
</select>  


【Map参数】
<select id="getStudentListWhereMap" parameterType="Map" resultMap="studentResultMap">  
    SELECT * from STUDENT_TBL ST  
     WHERE ST.STUDENT_SEX = #{sex}  
          AND ST.STUDENT_name = #{name}  
</select> 


【多参数实现】
如果想传入多个参数,则需要在接口的参数上添加@Param注解。给出一个实例: 
public List<StudentEntity> getStudentListWhereParam(@Param(value = "name") String name, @Param(value = "sex") String sex, @Param(value = "birthday") Date birthdar, @Param(value = "classEntity") ClassEntity classEntity);  


应用如下:
<select id="getStudentListWhereParam" resultMap="studentResultMap">  
    SELECT * from STUDENT_TBL ST  
    <where>  
        <if test="name!=null and name!='' ">  
            ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{name}),'%')  
        </if>  
        <if test="sex!= null and sex!= '' ">  
            AND ST.STUDENT_SEX = #{sex}  
        </if>  
        <if test="birthday!=null">  
            AND ST.STUDENT_BIRTHDAY = #{birthday}  
        </if>  
        <if test="classEntity!=null and classEntity.classID !=null and classEntity.classID!='' ">  
            AND ST.CLASS_ID = #{classEntity.classID}  
        </if>  
    </where>  
</select>


7、#{}与${}的区别


默认情况下,使用#{}语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义。 
示例1: 
执行SQL:Select * from emp where name = #{employeeName} 
参数:employeeName=>Smith 
解析后执行的SQL:Select * from emp where name = ? 
执行SQL:Select * from emp where name = ${employeeName} 
参数:employeeName传入值为:Smith 
解析后执行的SQL:Select * from emp where name =Smith


说明: 
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #{user_id},如果传入的值是111,那么解析成sql时的值为order by “111”, 
   如果传入的值是id,则解析成的sql为order by “id”.
 
2. $将传入的数据直接显示生成在sql中。如:order by ${user_id},如果传入的值是111,那么解析成sql时的值为order by 111, 如果传入的值是id,则解析成的sql为order by id.


综上所述,${}方式会引发SQL注入的问题、同时也会影响SQL语句的预编译,所以从安全性和性能的角度出发,能使用#{}的情况下就不要使用${}。


${}在什么情况下使用呢?


有时候可能需要直接插入一个不做任何修改的字符串到SQL语句中。这时候应该使用${}语法。


比如,动态SQL中的字段名,如:ORDER BY ${columnName}


<select id="queryMetaList" resultType="Map" statementType="STATEMENT">
    Select * from emp where name = ${employeeName} ORDER BY ${columnName}
</select> 


由于${}仅仅是简单的取值,所以以前sql注入的方法适用此处,如果我们order by语句后用了${},那么不做任何处理的时候是存在sql注入危险的。 




8、Mybatis调用存储过程 xml示例代码如下:


--------------------------------------------存储过程基本调用-------------------------------------------------------------
create procedure sptest.adder(in addend1 integer, in addend2 integer, out theSum integer)  
begin atomic  
  set theSum = addend1 + addend2;   
end  
go  


<parameterMap type="map" id="testParameterMap">  
   <parameter property="addend1" jdbcType="INTEGER" mode="IN"/>  
   <parameter property="addend2" jdbcType="INTEGER" mode="IN"/>  
   <parameter property="sum" jdbcType="INTEGER" mode="OUT"/>  
</parameterMap>  


<update id="adderWithParameterMap" parameterMap="testParameterMap" statementType="CALLABLE">  
   {call sptest.adder(?, ?, ?)}  
</update> 


JAVA调用
public void testAdderAsUpdateWithParameterMap() {  
       SqlSession sqlSession = sqlSessionFactory.openSession();  
       try {  
           Map<String, Object> parms = new HashMap<String, Object>();  
           parms.put("addend1", 3);  
           parms.put("addend2", 4);  
             
           SPMapper spMapper = sqlSession.getMapper(SPMapper.class);   
           spMapper.adderWithParameterMap(parms); 


           assertEquals(7, parms.get("sum")); 
             
       } finally {  
           sqlSession.close();  
       } 
}


----------------------------------------带输入输出参数的存储过程------------------------------------------------------------------------------
create procedure sptest.getnames(in lowestId int, out totalrows integer)    
BEGIN ATOMIC  
  declare cur cursor for select * from sptest.names where id >= lowestId;  
  select count(*) into totalrows from sptest.names where id >= lowestId;  
  open cur;  
END  
go
 
<select id="getNames" parameterType="java.util.Map" statementType="CALLABLE" resultMap="nameResult">  
  {call sptest.getnames(  
    #{lowestId,jdbcType=INTEGER,mode=IN},  
    #{totalRows,jdbcType=INTEGER,mode=OUT})}  
</select>      


JAVA调用
public void testCallWithResultSet2_a1() {  
       SqlSession sqlSession = sqlSessionFactory.openSession();  
       try {  
           SPMapper spMapper = sqlSession.getMapper(SPMapper.class);  
             
           Map<String, Object> parms = new HashMap<String, Object>();  
           parms.put("lowestId", 1);  
           List<Name> names = spMapper.getNamesAnnotated(parms);  
           assertEquals(3, names.size());  
           assertEquals(3, parms.get("totalRows"));  
       } finally {  
           sqlSession.close();  
       }  

---------------------------------------返回多个结果集------------------------------------------------------
create procedure sptest.getnamesanditems()  
reads sql data  
dynamic result sets 2  
BEGIN ATOMIC  
  declare cur1 cursor for select * from sptest.names;  
  declare cur2 cursor for select * from sptest.items;  
  open cur1;  
  open cur2;  
END  
go 


<resultMap type="org.apache.ibatis.submitted.sptests.Name" id="nameResult">  
    <result column="ID" property="id"/>  
    <result column="FIRST_NAME" property="firstName"/>  
    <result column="LAST_NAME" property="lastName"/>  
</resultMap>  
  
<resultMap type="org.apache.ibatis.submitted.sptests.Item" id="itemResult">  
    <result column="ID" property="id"/>  
    <result column="ITEM" property="item"/>  
</resultMap>  
  
<select id="getNamesAndItems" statementType="CALLABLE"  
    resultMap="nameResult,itemResult">  
    {call sptest.getnamesanditems()}  
</select>  


JAVA调用
public void testGetNamesAndItems() throws SQLException {  
        SqlSession sqlSession = sqlSessionFactory.openSession();  
        try {  
            SPMapper spMapper = sqlSession.getMapper(SPMapper.class);  
              
            List<List<?>> results = spMapper.getNamesAndItems();  
            assertEquals(2, results.size());  
            assertEquals(4, results.get(0).size());  
            assertEquals(3, results.get(1).size());  
        } finally {  
            sqlSession.close();  
        }  
}  





















































0 0
原创粉丝点击