MyBatis学习之SQL查询参数以及增删改操作
2016-12-20 11:26
295 查看
关于SQL语句中的参数问题
传统的JDBC中SQL参数输入有两种,一种是通过拼串的方式,这种方式可能会出现sql注入,也就是用户会输入一些sql语句,比如or 1=1,这样会引起安全问题以及每次都会进行重新编译效率偏低,还有一种是通过占位符?,它则会进行预编译,多次执行相同的sql而参数不一样时效率高,因为jdbc编译时只会识别字符串,通过占位符?可以使得sql语句相同,编译器不会再次编译,直接执行,而sql拼串,只有当sql完全一样时才不会进行编译,其他时候都需要进行编译,所以效率低。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)*pageSize select * 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,加行级锁
相关文章推荐
- MyBatis学习笔记-注解SQL多个参数查询异常处理
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- mybatis学习之二、SQL语句映射文件(2)增删改查、参数、缓存
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- Ibatis/mybatis中,查询SQL参数和返回都是Map的情况
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- mybatis 学习 二、SQL语句映射文件(2)增删改查、参数、缓存
- JDBC以及相关技术学习(四)----运载SQL进行查询交通工具Statement
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- SQL学习笔记[1] - 防注入攻击:一个参数传值+模糊查询的参考写法
- ThinkPHP学习笔记(八)CURD的的相关操作以及表的关联查询等
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- Nhibernate操作原生SQL以及查询DataTable
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存
- MyBatis学习 之 三、SQL语句映射文件-增删改查、参数、缓存
- Hibernate(二)HQL&SQL参数绑定、投影和分页以及命名查询
- MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存