您的位置:首页 > 数据库

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 SQL
相关文章推荐