面试题 关于SelectKey
来源:互联网 发布:外汇收入 知乎 编辑:程序博客网 时间:2024/06/06 01:39
题目:
Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?
注:这道题是京东面试官面试我时问的。
答:还有很多其他的标签,<resultMap>、<sql>、<include>、<selectKey>,加上动态sql的9个标签,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中<sql>为sql片段标签,通过<include>标签引入sql片段,<selectKey>为不支持自增的主键生成策略标签。
讲解:
在使用MyBatis做持久层时,insert语句默认是不返回记录的主键值,而是返回插入的记录条数;如果业务层需要得到记录的主键时,可以通过配置SelectKey的方式来完成这个功能。SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题,他可以很随意的设置生成主键的方式。
selectKey Attributes
属性
描述
keyProperty
selectKey 语句结果应该被设置的目标属性。
resultType
结果的类型。MyBatis通常可以算出来,但是写上也没有问题。MyBatis允许任何简单类型用作主键的类型,包括字符串。
order
这可以被设置为 BEFORE或 AFTER。如果设置为BEFORE,那么它会首先选择主键,设置keyProperty 然后执行插入语句。如果设置为AFTER,那么先执行插入语句,然后是selectKey 元素-这和如Oracle 数据库相似,可以在插入语句中嵌入序列调用。
statementType
和前面的相 同,MyBatis支持 STATEMENT ,PREPARED和CALLABLE语句的映射类型,分别代表PreparedStatement 和CallableStatement类型。
SelectKey需要注意order属性,像MySQL一类支持自动增长类型的数据库中,order需要设置为after才会取到正确的值。
步骤:
一:创建maven项目
Maven默认的Java版本是1.6,无法使用lambda表达式(1.8)和钻石运算符(1.7)
代码片段:pom.xml在pom.xml中,添加mybatis依赖,mysql-jdbc依赖,把编译版本改为1.8
你问,为啥mybatis不会自动依赖mysql-jdbc,需要手动写明?答:因为mysql驱动是通过字符串动态加载的,这是一种“动态依赖”,Maven只能推导出“静态依赖”。“动态依赖”是一种更加灵活的依赖
<!--MyBatis核心jar包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.2</version>
</dependency>
<!--MySQL配置-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf8</encoding>
</configuration>
</plugin>
</plugins>
</build>
最终的目录结构:
二:配置MyBatis
代码片段:mybatis.xml
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<propertiesresource="config.properties">
</properties>
<environmentsdefault="development">
<environmentid="development">
<transactionManagertype="JDBC"/>
<dataSourcetype="POOLED">
<propertyname="driver"value="${driver}"/>
<propertyname="url"value="${url}"/>
<propertyname="username"value="${username}"/>
<propertyname="password"value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapperclass="haha.UserDao"/>
<mapperresource="user.xml"/>
</mappers>
</configuration>
三:创建实体类User
User有三个属性:name,age和id,重写toString()方法便于调试。
public class User {
String name;
Integer age;
Integer id;
public User(){}
public User(String name,intage){
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age= age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id= id;
}
@Override
publicString toString() {
return String.format("(id:%d,name:%s,age:%d)",id, name,age);
}
}
相应的,在数据库中建立一个表user
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(10) DEFAULT NULL,
`age` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=119 DEFAULT CHARSET=utf8mb4
四:实现UserDao接口
UserDao接口有两个功能:插入、查询全部
public interface UserDAO {
@Insert("insert into user(name,age) value (#{name},#{age})")
int insert_withoutPrimaryKey(@Param("name") String name,@Param("age")int age);
int insert_useGeneratedKey(@Param("user") User user);
int insert_selectKey(@Param("user") User user);
@Insert("insert into user(name,age) value(#{user.name},#{user.age})")
@SelectKey(statement = "select last_insert_id()",keyProperty = "user.id",before = false,resultType =int.class)
int insert_selectKeyAnotation(@Param("user") User user);
@Select("select*from user")
List<User> getAll();
}
Mybatis写SQL语句有两种方式:1、使用注解;2、使用xml
对于比较长的SQL语句放在xml中,对于比较短的SQL语句放在注解中
在上面定义的UserDao中,insert_userGeneratedKey()和insert_selectKey()两个函数没有给出对应的SQL语句,需要在xml文件中进行定义。
代码片段:user.xml
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="haha.UserDao">
<insertid="insert_useGeneratedKey"parameterType="haha.User"
useGeneratedKeys="true"keyProperty="user.id">
insert into user set id=#{user.id},name=#{user.name},age=#{user.age}
</insert>
<insertid="insert_selectKey"parameterType="haha.User">
<selectKeykeyProperty="user.id"keyColumn="id"order="AFTER"resultType="int">
SELECT last_insert_id()
</selectKey>
insert into user(name,age) VALUE (#{user.name},#{user.age})
</insert>
</mapper>
五:测试
编写一个UserService类测试一下
package haha;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserService {
public static void main(String[] args)throws IOException {
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = newSqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);
SqlSession session = factory.openSession();
UserDao dao = session.getMapper(UserDao.class);
//使用默认主键
intaffectedRows = dao.insert_withoutPrimaryKey("张三",25);
System.out.println(affectedRows);
//使用useGeneratedKey,将主键注入到user.id中
User u = newUser("李四",17);
affectedRows = dao.insert_useGeneratedKey(u);
System.out.println(affectedRows +" " + u.getId());
//使用selectKey执行在插入之前或之后执行查询语句
affectedRows = dao.insert_selectKey(u);
System.out.println(affectedRows +" " + u.getId());
//使用selectKey注解的方式
affectedRows = dao.insert_selectKeyAnotation(u);
System.out.println(affectedRows +" " + u.getId());
session.commit();
List<User> a = dao.getAll();
a.forEach(System.out::println);
}
}
六:关于SelectKey
下面介绍一个重要注解
@SelctKey(statement="SQL语句",keyProperty="将SQL语句查询结果存放到keyProperty中去",before="true表示先查询再插入,false反之",resultType=int.class)
· statement是要运行的SQL语句,它的返回值通过resultType来指定
· before表示查询语句statement运行的时机
· keyProperty表示查询结果赋值给代码中的哪个对象,keyColumn表示将查询结果赋值给数据库表中哪一列
· keyProperty和keyColumn都不是必需的,有没有都可以
· before=true,插入之前进行查询,可以将查询结果赋给keyProperty和keyColumn,赋给keyColumn相当于更改数据库
· befaore=false,先插入,再查询,这时只能将结果赋给keyProperty
· 赋值给keyProperty用来“读”数据库,赋值给keyColumn用来写数据库
· selectKey的两大作用:1、生成主键;2、获取刚刚插入数据的主键。
· 使用selectKey,并且使用MySQL的last_insert_id()函数时,before必为false,也就是说必须先插入然后执行last_insert_id()才能获得刚刚插入数据的ID。
- 面试题 关于SelectKey
- 关于selectKey
- 关于一道面试题
- 关于一道面试题
- 关于面试题
- 【面试题】关于指针
- 关于一些面试题。
- 关于String面试题
- 关于String面试题
- 关于AJAX面试题
- SelectKey
- selectKey
- selectKey
- 关于Servlet的面试题
- 关于.NET软件工程师面试题
- 关于Tencent的面试题
- 关于Servlet的面试题
- 关于概率的面试题
- GPUImge学习日记(3) 之滤镜组合使用
- Python split() 函数 拆分字符串 将字符串转化为列
- 阿里巴巴淘票票专家分享:如何利用阿里云ARMS,搭建国际化在线售票的业务监控系统
- jsp中<c:forEach>的用法
- 二叉树中和为某一值的路径
- 面试题 关于SelectKey
- MongoDB常用操作指令
- linux 处理两个文件的并集,交集,计数
- 系统相关功能开发(八)-消息
- [NOIP模拟赛]传递情报
- okhttp上传
- Android Studio配置OpenCV+Tesseract-OCR识别图片
- Java之网络编程(二)UDP
- Hadoop与spark性能比较试验