这一节的学习强烈建议实际操作
主键自增和自定义主键
实现描述:我们在写程序时,时常会遇到这样的问题:插入一条数据,但因有主键的存在,而有时候会报“违反唯一性约束”的错误,我们可以使用如下方式解决
insert into t_role(role_name,note) values (#{roleName},#{note})
我们使用keyProperty属性指定id为主键字段,同时使用useGeneratedKeys属性告诉MyBatis这个主键是否使用数据库的内置规则生成。
mybatis参数传递
mybatis参数传递过程中,如果多个参数正好是我们业务逻辑的数据模型,我们可以直接传入pojo,#{属性名}取出属性值。
如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,我们可以采用map进行参数传递,#{key}取出map中的值。
如果多个参数不是业务模型中的数据,没有对应的pojo,经常使用,新建立一个数据实体类来进行接收参数,#{key}取出map中的值。
字符串传递参数
@Param 指定在mapper文件中需要使用的名称,多个参数传递的时候请指定,否则mapper文件可能接收不到数据值public User selectUser(@Param("userName") String name, int @Param("deptId") deptId);
map传递参数
public User selectUser(Mapparams);
#{}里面的名称对应的是Map里面的key名称。
Java Bean传参法
public User selectUser(User user);
#{} ,${}区别
使用${}方式传入的参数,mybatis不会对它进行特殊处理,而使用#{}传进来的参数,mybatis默认会将其当成字符串。可能在赋值给如id=#{id}和id=${id}看不出多大区别,但是作为表名或字段参数时可以明显看出,可以看看下面的例子:
selec * from #{table} => select * from "test";select * from ${table} => select * from test;
很明显,前者多了字符串的引号,会失败,后者正常查询会成功; 所以对于传入分组(order)字段或者排序字段(order),应使用${},避免出现order by "id" 等情况。
#和$在预编译处理中是不一样的。#类似jdbc中的PreparedStatement,对于传入的参数,在预处理阶段会使用?代替,比如:
select * from student where id = ?;
待真正查询的时候即在数据库管理系统中(DBMS)才会代入参数。 而${}则是简单的替换,如下:
select * from student where id = 2;
总结
1、能使用#{}的地方应尽量使用#{}
2、像PreparedStatement ,#{}可以有效防止sql注入,${}则可能导致sql注入成功。所谓sql注入,就是指把用户输入的数据拼接到sql语句后面作为sql语句的一部分执行,例如:
select * from user where name=${username} and password=#{passsword}select * from user where name=' admin ' and password='123456' or 'abc'= 'abc';
用户输入用户名 username=admin,password为password='123456' or 'abc'= 'abc';这样sql注入成功。
防止sql注入的几种方式
-
jdbc使用 PreparedStatement代替Statement, PreparedStatement 不仅提高了代码的可读性和可维护性.而且也提高了安全性,有效防止sql注入;
-
程序代码中使用正则表达式过滤特殊字符。
-
前端代码过滤特殊字符
MyBatis结果集映射(ResultMap)
Mybatis的查询可以将查询出的结果集转换成Java对象。ResultMap有以下几种用途:
- 如果数据表的列名和Java对象的属性名不一致,在ResultMap中可以进行关联
- 定义一对一的关联
- 定义一对多的关联
sql如下
CREATE TABLE t_user ( id INT(10) NOT NULL AUTO_INCREMENT, loginId VARCHAR(20) DEFAULT NULL, userName VARCHAR(100) DEFAULT NULL, roleId INT(10), note VARCHAR(255) DEFAULT NULL, PRIMARY KEY (id)) ENGINE=INNODB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8; INSERT INTO t_user(loginId,userName,roleId,note) VALUES ('queen', '奎恩', 1, '专门负责提鞋的。。。');INSERT INTO t_user(loginId,userName,roleId,note) VALUES ('king', '金狮子', 2, '磁性果实能力');INSERT INTO t_user(loginId,userName,roleId,note) VALUES ('Lucy', '路西', 3, '打败多弗朗明哥。。。');=========================================================CREATE TABLE t_role ( id INT(10) NOT NULL AUTO_INCREMENT, roleName VARCHAR(20) DEFAULT NULL, PRIMARY KEY (id)) ENGINE=INNODB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8; INSERT INTO t_role(roleName) VALUES ('自定义角色');INSERT INTO t_role(roleName) VALUES ('前海贼');INSERT INTO t_role(roleName) VALUES ('未来海贼王');
实体对象
package com.springmvc.pojo;/** * @program: TestSSM * @description: * @author: lee * @create: 2019-03-25 **//** * @since 2017-08-08 * @author queen * 定义一个Java类Role * */public class Role { private int id; private String roleName; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Role(){ } public Role(int id, String roleName) { this.id = id; this.roleName = roleName; } @Override public String toString() { return "Role [id=" + id + ", roleName=" + roleName + "]"; }}package com.springmvc.pojo;/** * @program: TestSSM * @description: * @author: lee * @create: 2019-03-25 **//** * @since 2017-08-08 * @author queen * 定义一个Java类 * */public class User { // ID,唯一性 private int id; // 登录ID private String loginId; // 用户名 private String userName; // 角色 private Role role; // 备注 private String note; public User(){ } public User(int id, String loginId, String userName, Role role, String note) { this.id = id; this.loginId = loginId; this.userName = userName; this.role = role; this.note = note; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLoginId() { return loginId; } public void setLoginId(String loginId) { this.loginId = loginId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Role getRole() { return role; } public void setRole(Role role) { this.role = role; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } @Override public String toString() { return "User [id=" + id + ", loginId=" + loginId + ", userName=" + userName + ", role=" + role + ", note=" + note + "]"; }}
最基本的映射方式
嵌套映射
第三种方式
collection用法和association用方法类似
因为修改了表字段和Java实体属性,数据库里面运行如下sql语句
-- ------------------------------ Table structure for `t_role`-- ----------------------------DROP TABLE IF EXISTS `t_role`;CREATE TABLE `t_role` ( `id` int(10) NOT NULL AUTO_INCREMENT, `roleName` varchar(20) DEFAULT NULL, `role_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ------------------------------ Records of `t_role`-- ----------------------------BEGIN;INSERT INTO `t_role` VALUES ('1', '自定义角色', '1'), ('2', '前海贼', '1'), ('3', '未来海贼王', '2');COMMIT;
Role实体类如下
package com.springmvc.pojo;/** * @program: TestSSM * @description: * @author: lee * @create: 2019-03-25 **//** * @since 2017-08-08 * @author queen * 定义一个Java类Role * */public class Role { private int id; private String roleName; private String roleId; public String getRoleId() { return roleId; } public void setRoleId(String roleId) { this.roleId = roleId; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Role(){ } public Role(int id, String roleName) { this.id = id; this.roleName = roleName; } @Override public String toString() { return "Role [id=" + id + ", roleName=" + roleName + "]"; }}
mapper 文件如下
数据库查询结果