Mybatis入门程序数据操作(3)
内容接着上一篇文章,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为例:
- 通过Mysql的函数SELECT LAST_INSERT_ID()来获取刚刚插入记录的自增主键(即取出最后一个主键)。
这里order参数表示该SQL函数相对于insert语句的执行时间,有BEFORE和AFTER。这里程序执行完insert之后,就可以在测试类中,从user对象中直接拿到该id的信息(取出的主键信息会放置在输入参数user对象中)。
- 通过Mysql的函数SELECT LAST_INSERT_ID()来获取刚刚插入记录的自增主键(即取出最后一个主键)。
<!--在表中新增数据信息-->
<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>
- 在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'. 这样就会报错查询不到数据
- 关于“selectOne”与“selectList”:
它们都属于SqlSession类提供的方法,在使用查询语句时,如果查询的数据只有一条数据,那么可以使用“selectOne”方法进行查询;如果查询的数据可能多于一条,那么可以使用“selectList”方法进行查询。 - MyBatis与Hibernate区别:
MyBatis的特点就是以SQL语句为核心的不完全的ORM(关系型映射)框架。与Hiberna相比,Hibernate的学习成本比较高,而SQL语句并不需要开发人员完成,只需调用相关API即可。这对于开发效率是一个优势,但是缺点时没办法对SQL语句进行优化和修改。而MyBatis虽然需要开发人员自己配置SQL语句,MyBatis来实现映射关系,但是这样的项目可以适应经常变化的项目需求。所以,使用MyBatis的场景是:对SQL优化要求比较高,或是项目需求或业务经常变动。