MyBatis学习之SQL查询参数以及增删改操作

来源:互联网 发布:成都 大数据 售前 编辑:程序博客网 时间:2024/06/05 01:54

关于SQL语句中的参数问题

  1. 传统的JDBC中SQL参数输入有两种,一种是通过拼串的方式,这种方式可能会出现sql注入,也就是用户会输入一些sql语句,比如or 1=1,这样会引起安全问题以及每次都会进行重新编译效率偏低,还有一种是通过占位符?,它则会进行预编译,多次执行相同的sql而参数不一样时效率高,因为jdbc编译时只会识别字符串,通过占位符?可以使得sql语句相同,编译器不会再次编译,直接执行,而sql拼串,只有当sql完全一样时才不会进行编译,其他时候都需要进行编译,所以效率低。
  2. MyBatis框架中SQL参数的输入也是有两种拼串和占位符,由于框架将sql和程序代码分离开,所以无法直接确认参数占位符的含义,所以框架采用特殊的符号来代替占位符#{}和${},前者会将参数加上引号,后者直接按原样输出。所以一般前者用来在作为条件查询的参数,而后者则用来直接拼接到SQL语句中执行,因此我们在传参数时就应当注意占位符的选择。
    a.当传一个参数时,参数名称可以随便写,MyBatis会直接取值
    b.当需要多个参数时,如果传入的参数少于需要的参数,所有的取值就会都完全相同,这时参数名称就可以随便命名,但是将查不到数据,而不会报错。传递多个参数时可以通过自定义的类型传递,sql文的参数会从自定义的类型的属性当中取值,但参数名必须和属性的名称相同,SQL执行时会根据参数名称通过反射调用对象中的方法,当相同名称的属性不存在时会发生异常。也可以通过集合类型(Map)来传递多个参数,sql文中会从map集合中的key获取参数值,所以参数的名称必须和map中的key保持一致,如果map中不存在和该参数名称相同的key,参数则自动null,同样查询不到数据。各应用场景:sql中只有一个参数时使用基本类型传参,sql中多个参数且有相同的含义,使用自定义类型传参,当多个参数之间没有任何关系时就使用map来传递参数。

注意表名和列名以及排序的字段不能使用占位符,其中表名和排序的字段使用占位符会报错,而列名使用占位符查询的结果不正确,由于占位符一般都是传递条件的,也就是在where子句中使用,对于其他的则需要进行拼串操作,这时就需要特殊的符号进行拼串操作,即${},通过此种方式传参数,参数作为sql文的一部分执行,也就是拼串操作,所以这时就应该注意sql注入的问题,如果是条件中使用参数,那么必须采用占位符,如果其他的场合,可以采用拼串,而且如果是用户输入的,也不能采用拼串的方式
3.关于模糊查询中的参数格式问题:

select * from t_user where username like '%admin%';

由于admin是需要外部传递参数进来,此时就需要注意参数的格式问题,可通过以下格式:

select * from t_user where username like '%${username}%';

但是不安全,因为在条件中进行了拼串的操作,必须采用占位符,就可以在后台加上%%后再将参数传进去

select * from t_user where username like #{username};

但是不方便,Java代码和sql语句的耦合性太高,应该各自独立,这时可以通过不同的数据库采用不同的方式来实现sql的字符串的拼接操作
MySQL:concat(s1,s2,s3…..)

select * from t_user where username like concat('%',#{username},'%');

Oracle和DB2:通过||或concat(s1,s2,s3…..)来进行拼串

select * from t_user where username like '%'||#{username}||'%';

或者

SELECT * FROM t_user WHERE name like CONCAT('%',#{name},'%')  

SQLServer:通过+拼接

SELECT * FROM t_user WHERE name like '%'+#{name}+'%'

还有一种方式就是使用MyBatis自带的bind标签:

<select id="selectPersons" resultType="person" parameterType="person">        <bind name="pattern" value="'%' + _parameter.username + '%'" />        select id,sex,age,username,password from person where username LIKE #{pattern}  </select>  

4.MyBatis框架的输出,也就是sql的操作结果,增删改就返回数据库中被影响的数据条数。
resultType:该属性表示将查询结果转换为指定类型的对象,MyBatis框架是面向sql的,所以对像和sql没有关系,将查询结果转换为指定类型的对象时,需要遵循转换的规则,将查询结果字段名称和指定类型的属性名称进行匹配,如果匹配成功则反射调用,如果匹配不成功,什么也不做,在极限情况下,一个属性都没有匹配成功,那么对象不会创建,获取null,当名称不一致时也希望转换成功,那么需要改名,即将查询的结果使用别名,as xxxx,而且也可以将查询的结果字段的名称通过独立的配置方式进行改变,如下:

<resultMap type="com.ecjtu.test.bean.User",id=userMap>    <result column="ID" jdbcType="VARCHAR" property="id" />    <result column="password" property="password"/></resultMap><select id="selectUsers" resultMap="userMap">    select * from t_user</select>

查询的结果转换为指定的类型:
a.自定义类型:(获取数据之间存在关系时使用)
将查询结果字段名称和自定义类型的属性名称一一对应
b.将查询结果转换为map(获取的数据之间没有任何关系时使用)

resultType="java.util.HashMap"

将查询结果字段名作为key,将查询结果值作为val,形成键值对的形式
c.基本数据类型

resultType="java.lang.String"

返回的是查询结果的第一个字段值
5.有关MyBatis的分页查询问题:
a.逻辑分页
一次性将数据库中所有数据查询出来,放置在缓存中,通过逻辑算法获取指定页码的数据,这种分页方式称为逻辑分页,这种方式查询效率快(内存操作),但第一次查询所有的数据可能会很慢,因为不确定数据库中有多少数据,如果数据量大的话就会很慢,会查询很多用户根本用不到的数据
而且会占用大量内存,降低了服务器的性能

RowBounds rb = new RowBounds((pageNo-1)*pageSize,pageSize);session.selectList(sqlId,argObject,rowBounds);

b.物理分页
采用数据库本身的分页机制来实现分页查询操作,称之为物理分页,效率低(进程操作),但是一般使用这种,因为这种方式最适合我们的业务需要,毕竟客户只是想要翻页查看他们想要的数据,而不会一直去翻所有页的数据
mysql:limit 0(可省略不写),pagesize,limit startIndex,pagesize

int pageno = 1;int pageSize = 5;int pageIndex = (pageno-1)*pageSizeselect * from t_user limit #{pageIndex},#{pageSize};

oracle:三层查询嵌套 + rowNum

select * from t_user where rownum > 5 and rownum <= 10;

由于oracle中rownum大于等于的条件是不支持的

select * from (        select t.*, rownum as num from t_user where rownum <= 10        )where num > 5

又由于rownum无法和order by语句在一起使用

select * from (        select t.*, rownum as num from(            select * from t_user order by regdate        )t        where rownum <= 10)where num > 5

注意:
嵌套查询其实很慢,我们可以根据需要进行选择,当从第一条数据并且没有排序的分页查询时,就可以只使用一层,当没有排序时使用两层,都有时才使用三层嵌套查询
6.数据库三个术语:
DDL:数据库定义语言,create drop
DML:数据库操作语言,insert delete update,涉及到事物的提交和回滚
DQL:数据库查询语言,select
增删改操作的SQL:

<!-- 主键使用自增长 --><insert id="addUser" parameterType="com.ecjtu.mybatis.entity.User" useGeneratedKeys="true" keyProperty="id">    insert into user values(#{id},#{userName},#{userAge},#{userAddress})</insert>
<update id="updateUser" parameterType="User">        update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id=#{id}</update> 
<delete id="deleteUser" parameterType="int">        delete from user where id=#{id}</delete>

如果表的主键是自增长的,那么在插入数据之后需要立即获取自增长的主键值,而且MySql中自增长的一定是int类型,获取自增长主键格式如下:

<insert>    insert into tab_user (    username,password    )values(        #{username},        #{password},    )    <selectKey keyProperty="id" resultType="java.lant.Integer">        select @@identity as id    </selectKey></insert>

Oracle:自增长的类型可以为int,也可以为String

insert into tab_user(id) values(userseq.nextval)<selectKey keyProperty="id" resultType="java.lant.Integer">        select userseq.currval from dual</selectKey>

7.有关数据库的事物
传统的JDBC事物管理方式:

try{    conn.setAutoCommit(false);}catch{    conn.rollback();}finally{    conn.commit();    conn.setAutoCommit(true);}

MyBatis中底层事物管理方式:没有提交就会在finally语句块中进行回滚,session.close()操作里面内含了回滚的操作

try{    session.commit();}finally{    session.close();}

0.事务的边界 :Service层
1.事务的传播行为 :多个事务在嵌套使用时的处理方式
2.事物的隔离级别: select * from t_user where id = 1 for update,加行级锁

0 0
原创粉丝点击