Mybatis入门程序数据操作(3)

作者: LeaveStyle | 来源:发表于2018-08-30 15:18 被阅读1次

    内容接着上一篇文章,Mybatis搭建环境(2)

    先把dao层的接口给出来,和UserMapper.xml中的mapper标签的namespace属性对接。

    package cn.com.mybatis.dao;
    import cn.com.mybatis.po.User;
    
    public interface UserDao {
        User findUserById(int id);
        User findUserByUsername(String username);
        int insertUser(User user);
        int deleteUser(int id);
        User updateUserName(String username);
    }
    

    1. 模糊查询样例

    要对数据库中User表的数据进行模糊查询,需要通过匹配名字的某个字来查询该用户,首先在UserMapper.xml文件中配置SQL映射:

    <!--根据用户姓名进行模糊查询-->
    <select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.com.mybatis.po.User">
        SELECT * FROM USER WHERE username LIKE '%${value}'
    </select>
    

    这里“${}”符号表示拼接SQL串,将收到的参数内容不加任何修饰地拼接在SQL中,在“${}”中只能使用value代表其中的参数。然而在Web项目中,如果没有防范SQL注入的机制,要谨慎使用“${}”符号拼接SQL语句串,因为这可能会引起SQL注入的风险。
    然后在MyBatisTest测试类中写一个新的测试方法TestFuzzySearch,来查询所有名称中含有“丽”字的用户信息。

    @Test
        public void TestFuzzySearch() throws IOException{
            SqlSession sqlSession = dataConn.getSqlSession();
            List<User> userList = sqlSession.selectList("cn.com.mybatis.dao.UserDao.findUserByUsername","丽");
            for(User user : userList){
                System.out.println("姓名:"+user.getUsername());
                System.out.println("性别:"+user.getGender());
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                System.out.println("生日:"+sdf.format(user.getBirthday()));
                System.out.println("所在地:"+user.getProvince()+user.getCity());
            }
            sqlSession.close();;
        }
    
    模糊查询结果.png

    2. 新增样例

    要对数据库中User表进行新增数据,在UserMapper.xml文件中配置SQL映射:

    <!--在表中新增数据信息-->
    <insert id="insertUser" parameterType="cn.com.mybatis.po.User">
        INSERT INTO USER(username, password, gender, birthday, email, province, city)
          VALUE (#{username}, #{password}, #{gender}, #{birthday,jdbcType=DATE}, #{email}, #{province}, #{city})
    </insert>
    

    在测试类MyBatisTest中添加名为TestInsert方法,向User表新插入一条用户数据。

    @Test
    public void TestInsert() throws Exception{
        SqlSession sqlSession = dataConn.getSqlSession();
        User user = new User();
        user.setUsername("孙佳佳");
        user.setGender("男");
        user.setPassword("5555");
        user.setEmail("5555@126.com");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        user.setBirthday(sdf.parse("1991-02-16"));
        user.setProvince("湖北省");
        user.setCity("武汉市");
        sqlSession.insert("cn.com.mybatis.dao.UserDao.insertUser",user);
        sqlSession.commit();
        sqlSession.close();
    }
    
    插入数据成功页面.png
    更新后的表单信息.png

    如果想在插入之后不执行查询语句而立即获取id信息,有两种方法,这里针对Mysql为例:

      1. 通过Mysql的函数SELECT LAST_INSERT_ID()来获取刚刚插入记录的自增主键(即取出最后一个主键)。
        这里order参数表示该SQL函数相对于insert语句的执行时间,有BEFORE和AFTER。这里程序执行完insert之后,就可以在测试类中,从user对象中直接拿到该id的信息(取出的主键信息会放置在输入参数user对象中)。
    <!--在表中新增数据信息-->
    <insert id="insertUser" parameterType="cn.com.mybatis.po.User">
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO USER(username, password, gender, birthday, email, province, city)
          VALUE (#{username}, #{password}, #{gender}, #{birthday,jdbcType=DATE}, #{email}, #{province}, #{city})
    </insert>
    
      1. 在insert标签中添加属性“useGenerateKeys”和“keyProperty”,其中userGeneratedKeys表示使用自增主键,而keyProperty是Java对象的属性名。
    <!--在表中新增数据信息-->
    <insert id="insertUser" parameterType="cn.com.mybatis.po.User"
        useGeneratedKeys="true" keyProperty="id">
        INSERT INTO USER(username, password, gender, birthday, email, province, city)
          VALUE (#{username}, #{password}, #{gender}, #{birthday,jdbcType=DATE}, #{email}, #{province}, #{city})
    </insert>
    

    进行完上面的配置后,MyBatis执行完insert语句后,会自动将自增长id值赋给对象User的属性id,然后在逻辑处理层就可以通过User的get方法获得该id。

    3. 删除与修改样例

    对于删除和修改,同样需要在UserMapper.xml配置文件中编写相关的SQL配置:

    <!--删除用户-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        DELETE FROM USER WHERE id=#{id}
    </delete>
    <!--修改用户-->
    <update id="updateUserName" parameterType="cn.com.mybatis.po.User">
        UPDATE USER SET username=#{username} where id=#{id}
    </update>
    

    在MyBatisTest测试类中添加TestDelete和TestUpdate测试方法:

    @Test
    public void TestDelete() throws Exception{
        SqlSession sqlSession = dataConn.getSqlSession();
        sqlSession.delete("cn.com.mybatis.dao.UserDao.deleteUser",5);
        sqlSession.commit();
        sqlSession.close(); 
    }
    @Test
    public void TestUpdate() throws Exception{
        SqlSession sqlSession = dataConn.getSqlSession();
        User user = new User();
        user.setId(4);
        user.setUsername("孙丽");
        sqlSession.update("cn.com.mybatis.dao.UserDao.updateUserName", user);
        sqlSession.commit();
        sqlSession.close();
    }
    
    删除样例成功.png
    修改样例成功.png

    到此Mybatis的基本入门操作就完成了,下面补充一下注意的事项:

    • 关于parameterType:
      在执行SQL配置时,需要指定输入参数的类型。parameterType就是用来在SQL映射文件指定输入参数类型的。使用parameterType可以指定参数为基本数据类型(如 int、float等)、包装数据类型(Integer类、Double类)以及用户编写的JavaBean封装类。
    • 关于resultType:
      在加载SQL配置,并绑定制定输入参数和运行SQL之后,会得到数据库返回的相应结果,此时使用resultType来指定数据库返回的信息对应Java的数据类型。输出参数的类型为基本数据类型(如 int、float等)、包装数据类型(Integer类、Double类)以及用户自己编写的JavaBean的封装类。
    • 关于“#{}”:
      在SQL配置文件中,输入参数需要占位符来标识对应的位置。在传统的JDBC的编程中,占位符用"?"来表示,然后在加载SQL之前按照"?"的位置设置参数。在MyBatis中也是一种占位符,它接受输入参数,在大括号中编写参数名称来接受对应参数。“#{}”接受的可以是简单类型、普通JavaBean或者HashMap。里面可以写value或者其他名称。若接受的是JavaBean,它通过OGNL读取对象中的属性值,通过“属性1.属性2.属性3等”的方式获取对象属性值。
    • 关于“${}”:
      在SQL配置中,有时需要拼接SQL语句。例如在模糊查询时,就需要在查询条件的两侧拼接两个“%”字符串,这时“#{}”就不行。在MyBatis中,“${}”在SQL配置文件中表示的是一个“拼接符号”,可以在原有SQL语句上拼接新的符合SQL语法的语句。单用“${}”会引起SQL注入,慎用。另外,当接受简单类型时,“${}”中只能写“value”,而不能写其他名称。其他内容同上。

    注意 ${} 和 #{} 的区别:

    动态 sql 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前 mybatis 会对其进行动态解析。mybatis 为我们提供了两种支持动态 sql 的语法:#{} 以及 ${}。

    • ${}哪边都能使用,只是存在sql注入风险,相当于直接拼接字符串,不对参数做任何处理。
    • #{}会进行预编译,对参数进行处理,防止注入。
    <!--在下面的语句中,如果 username 的值为 zhangsan,则两种方式无任何区别:-->
    select * from user where name = #{name};
    select * from user where name = ${name};
    <!--解析出来的结果都是如下:-->
    select * from user where name = 'zhangsan';
    
    • 但是 #{} 和 ${} 在预编译中的处理是不一样的。#{} 在预处理时,会把参数部分用一个占位符 ? 代替,变成如下的 sql 语句:
    elect * from user where name = ?;
    
    • 而 ${} 则只是简单的字符串替换,在动态解析阶段,该 sql 语句会被解析成:
    select * from user where name = 'zhangsan';
    
    • 以上,#{} 的参数替换是发生在 DBMS 中,而 ${} 则发生在动态解析过程中。
      那么,在使用过程中我们应该使用哪种方式呢?
      答案是,优先使用 #{}。因为 ${} 会导致 sql 注入的问题。看下面的例子:
    select * from ${tableName} where name = #{name}
    <!--若表名为user; delete user; 则动态解析之后 sql 如下:-- -->
    select * from user; delete user; -- where name = ?;
    

    之后的语句被注释掉,而原本查询用户的语句变成了查询所有用户信息+删除用户表的语句,会对数据库造成重大损伤,极大可能导致服务器宕机

    • 既然这样那为什么还要用${}呢。
      因为使用#{}存在一个不足,当参数为字符串时会加上'',这就导致某些情况下sql失效。
      SELECT * FROM #{tableName},当使用#{}传入参数user,sql就会变成
      SELECT * FROM 'user'. 这样就会报错查询不到数据

    参考文章: Mabatis中#{}和${}的区别mybatis #{}与${}使用场景

    • 关于“selectOne”与“selectList”:
      它们都属于SqlSession类提供的方法,在使用查询语句时,如果查询的数据只有一条数据,那么可以使用“selectOne”方法进行查询;如果查询的数据可能多于一条,那么可以使用“selectList”方法进行查询。
    • MyBatis与Hibernate区别:
      MyBatis的特点就是以SQL语句为核心的不完全的ORM(关系型映射)框架。与Hiberna相比,Hibernate的学习成本比较高,而SQL语句并不需要开发人员完成,只需调用相关API即可。这对于开发效率是一个优势,但是缺点时没办法对SQL语句进行优化和修改。而MyBatis虽然需要开发人员自己配置SQL语句,MyBatis来实现映射关系,但是这样的项目可以适应经常变化的项目需求。所以,使用MyBatis的场景是:对SQL优化要求比较高,或是项目需求或业务经常变动。

    相关文章

      网友评论

        本文标题:Mybatis入门程序数据操作(3)

        本文链接:https://www.haomeiwen.com/subject/pohrwftx.html