在云笔记项目中,讲到了MySql的自增,MyBatis查询到自增类型数据后可以设置返回到参数属性,其中学习了MySql的自增写法,堆栈对象等知识。

MySql数据类型自增

建立一张Person表,其中id就是自增,而name为人为插入,以下就是MySql自增的写法,不同的数据库写法不太一致,个人比较熟悉的就是Oracle需要写一个Sequence来解决,而MySql的写法更加简单:

 --MyBatis数据自增,MySQL中使用AUTO_INCREMENT,ORACLE中使用SEQUENCE
CREATE TABLE P_PERSON(
id int not null AUTO_INCREMENT,
name VARCHAR(100),
PRIMARY KEY(id)
);

建立表后,插入的数据id自动增加,如图为插入一定数量的数据后所呈现的结果:

映射文件中写法

由于使用了MyBatis来插入数据,这次有两个新的属性“useGeneratedKeys”和“keyProperty”,其中useGeneratedKeys为true,代表可以读取自增的id,而keyProperty=“id”,代表MyBatis将读取的结果赋值给参数Person对象的id属性,以下是MyBatis映射文件的配置。

    <insert id="addPerson" parameterType="com.boe.Entity.Person" useGeneratedKeys="true" keyProperty="id">
insert into
p_person
values(
#{id},
#{name}
)
</insert>

使用Spring容器插入数据

简单的数据库插入操作,项目学习的过程中使用了DAO接口+映射文件+实体Person类+Spring启动容器的方式来完成,测试能否插入数据成功,以下是测试的代码,省略掉Spring初始化的部分代码,直接进入测试部分,看看能否完成数据插入。

     //测试插入一条Person信息
@Test
public void test() { Person person=new Person(null,"LOVE");
//第一次输出
System.out.println(person);//Person [id=null, name=LOVE]
//插入到数据库
int n=dao.addPerson(person);
System.out.println(n);
//第二次输出
System.out.println(person);//Person [id=5, name=LOVE]
}

测试结果能正常插入数据,输出结果如下:

可以看出第一次输出结果id为null,第二次输出结果却为5,并且name输出均为LOVE,关于这一块需要用到Java中的值传递,final关键字,堆栈等知识点。

第一次输出的id为null,第二次输出的id结果为5,其需要用堆栈的知识去理解, 第一次输出person,这个Person对象已经储存在堆中,并且Person对象包含两个属性,一个是Integer包装类属性,另一个是String类型属性。Person对象在堆中创建后,又分别创建Integer对象和String类型对象,其中Integer对象的值为null,而String类型对象底层使用一个Value数组来保存字符串,并且用final修饰,说明其长度不可以改变,如本次为数组长度4的LOVE。

接下来执行dao.addPerson(person)方法,底层会被MyBatis调用插入数据的操作,并且Java采用值传递,将Person对象的内存地址传递给方法中的person,因此方法中这个person地址跟前面那个一样,都指向堆中的Person对象。当MyBatis返回自增类型的id后,将值赋值到堆中的Integer,并覆盖为5,

最后MyBatis底层方法执行完成后,Spring会帮忙销毁addPersion()方法中的局部变量person,因此addPerson()方法中person变量在方法执行完成后在栈中消失,当第二次打印person对象时,此时其指向的对象id已经变成5,因此再次输出的结果就是5了。参考下图:

为了更好的理解堆栈对象概念,接下来刘老师又举了两个例子,如下所示:

测试内存堆栈对象-值传递String和StringBuilder

话不多说直接上测试代码,发现执行完add()方法后,String类型输出为A,而StringBuilder类型输出为AA。

     //再次测试内存堆栈,对象
@Test
public void test1() {
String s="A";
StringBuilder sb=new StringBuilder("A");
add(s,sb);
//输出
System.out.println(s);//A
System.out.println(sb);//AA
} /**
* 测试方法,传入一个String类型和StringBuilder类型
* @param s
* @param sb
*/
public static void add(String s,StringBuilder sb) {
s=s+"A";
sb.append("A");
}

可以参考上面person两次输出结果的原理,再次可以得出此次结果的原理:

刚开始String类型变量s和StringBuilder类型变量sb初始化后,都会在堆中建立String对象和StringBuilder对象,s和sb会储存在栈中指向堆中的对象,当执行add()方法后,s和sb对应的对象地址值会传入到参数s和sb中,此时依然都指向以前的对象。

当执行s=s+“A”方法后,由于s是String类型,其底层是用final关键字修饰了保存字符的value[]数组,因此长度不可变,如果想增加一个字符,需要在堆中另外创建一个对象,用于储存增加A的结果,如图所示显示为AA,并且参数s的地址转而指向新建的对象。

而StringBuilder是长度可以变的,因此在append()方法执行后,不需要新建立一个对象,直接在原来的对象基础上加A,变成了AA。

最后执行完add()方法后,方法中的参数(局部变量)将在栈中因垃圾回收机制被删除,因此最后输出结果依然是上面的两个栈所指向的对象内容,分别为A和AA。

测试内存堆栈对象-值传递Integer和int[]数组

继续测试,发现执行完doSome()方法后,Integer类型输出为2,而int[]类型输出为3。

     //再次测试内存堆栈,对象
@Test
public void test2() {
Integer i=2;//Integer包装类跟String类型,也是final修饰的,是不可变量
int[] array= {2};
doSome(i,array);
//输出执行完后结果
System.out.println(i);//
System.out.println(array[0]);//
} /**
* 测试方法,传入Integer包装类和int数组
* @param i
* @param array
*/
public static void doSome(Integer i,int[] array) {
i=i++;
array[0]++;
}

可以参考上面结果的原理,再次可以得出此次结果的原理:

与上面的原因类似,由于Integer也是final关键字修饰的,是值不可变量,因此也需要在堆中为i++创建一个对象进行储存,如图结果为3储存在堆Integer对象中,而Int[]自增的结果3不需要单独再创建一个对象。在方法doSome()执行完成后,方法中的i和array参数销毁,重新输出指向的对象结果就是上面两个,依次输出2和3。

然后如果在上面的方法中,对array数组的修饰使用final关键字,变成final int[] array={2}后,结果分别会是多少呢?测试发现结果依然分别为2和3。为什么final关键字修饰的array结果不是2,而依然是3,按理来说修饰完后其值不应该改变才对的。后面通过学习其他前辈的经验,发现,被final关键字修饰的变量其实就相当于定义了一个常量,是无法被修改的变量,如果final修饰的是一个基本数据类型的变量,那么这个变量的值就定了,不能变了,而如果修饰的是一个引用变量,如本例修饰的引用类型变量array,那么该变量存的是一个内存地址,该地址就不能变了,但是该内存地址所指向的那个对象还是可以变的,所以上面的数组被final修饰后,返回的类型不是2,依然是3,对象中的值依然是可以改变的。

结论

(1)MySql和Oracle都可以返回自增类型,写法不一样,前者用AUTO_INCREMENT,后者用序列SEQUENCE。

(2)Java中参数的传递采用值传递,当方法执行完成后,方法中的参数将会销毁

(3)final关键字修饰的如果是基本数据类型变量,这个变量就不能动了,如果修饰的引用类型变量,只是引用类型变量的地址不能变了,但是引用类型变量指向的对象却可能可以变化。

参考博客:https://blog.csdn.net/u013781343/article/details/80548378

云笔记项目-MyBatis返回自增类型&堆栈对象补充理解的更多相关文章

  1. mybatis返回HashMap结果类型与映射

    <!-- 返回HashMap结果 类型--> <!-- 如果想返回JavaBean,只需将resultType设置为JavaBean的别名或全限定名 --> <!-- T ...

  2. mybatis返回自增主键踩坑记

    背景 MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map ...

  3. 杜绝网上压根没测过就乱写之 《oracle mybatis 返回自增主键 》

    面试过好多人,包括自己也属于这么一个情况: 遇到问题直接去网上查,一般都可以查到解决方案.其中也包括一些基本的面试资料的答案. 其实有很多答案也都是正确的,但是还是存在一些压根就是胡乱抄来的答案,也不 ...

  4. 转mybatis返回自增主键,亲测

    重点是获取对象的主键值而不是insert的返回值 Mybatis获取插入数据的主键时,返回值总是1xml里的写法 第一种方式 <insert id="insertLogin" ...

  5. mybatis返回自增主键问题踩坑

    1 <insert id="insert" keyProperty="id" useGeneratedKeys="true"
 par ...

  6. Mybatis返回表自增id

    在Mapper中,设置insert中添加useGeneratedKeys = "true"   keyProperty = "id" keyColumn=&qu ...

  7. 返回多个类型的对象,Tuple

    一个方法 通常只有一个 返回对象,有时候 我们遇到 要放回两个不同类型的值的时候, 这个时候可以使用Tuple. 对象. Tupele 只支持 .net framework 4.0 以上版本. 来!先 ...

  8. mybatis+sqlserver中返回非自增主键

    首先把实体类贴出来(这里只贴出属性,其它的就是getter和setter方法): public class Around {     private String xccd;  //对应主键      ...

  9. MyBatis 返回新增数据的自增id

    <insert id="save" parameterType="Vote" useGeneratedKeys="true" keyP ...

随机推荐

  1. mi家前端面经

    已经好久没想写面经了……菜鸟面到生无可恋. 1.用CSS实现下面圆形 答案: <!DOCTYPE html> <html> <head> <style typ ...

  2. 使用uiautomator2进行webview页面的测试

    1.开发开启webview debug模式 2.使用VirtualXposed框架进行webview测试,详细见https://testerhome.com/topics/16156 下载,安装Vir ...

  3. Python import与from import使用及区别介绍

    Python程序可以调用一组基本的函数(即内建函数),比如print().input()和len()等函数.接下来通过本文给大家介绍Python import与from import使用及区别介绍,感 ...

  4. Centos7修改默认网卡名(改为eth0)以及网卡启动报错RTNETLINK answers: File exists处理

    安装好centos7版本的系统后,发现默认的网卡名字有点怪,为了便于管理,可以手动修改.下面对centos7版本下网卡重命名操作做一记录:1)编辑网卡信息[root@linux-node2~]# cd ...

  5. spring boot profiles 实现多环境下配置切换 docker版

    1,前言 开发环境总需要调试,docker直接部署不需要调试,环境配置不一样,这里的目的只是,在docker文件环境与开发环境使用不同的配置文件,项目结构如下 2,设置项目配置文件 默认配置文件 ap ...

  6. 01-使用eclipse新建一个标准的 java web项目

    1.使用eclipse创建个普通的Java SE项目  名称:CRM java web标准目录结构 crm WEB-INF classes lib web.xml 设置项目字节码输出目录

  7. html+css+jq随记

    随便写个博客吧,记录一下自己的历程,今天忽然用自己好久不用的jq还做项目,并且从零开始搭建,让自己慌乱不已啊!遇到了如下问题 1.ios端点击闪屏的问题,解决办法如下 在body上添加 -webkit ...

  8. Android View添加删除或隐藏显示的默认动画;

    代码中给控件设置Visibility ? VISIBLE : GONE ;时太生硬,用户体验不好:设置一个Android ViewGroup的默认动画很实用: 给需要添加动画的控件或布局的父布局,记住 ...

  9. JavaScript数组方法--every、some、fill

    接上一篇,JavaScript数组方法--concat.push,继续其他的数组方法. every:every() 方法测试数组的所有元素是否都通过了指定函数的测试. 先看其使用方法: functio ...

  10. 十进制 -> 十六进制

    x /16 依次取余 ,最先余作十六进制的最低 字节有效位,最后的余数  作最高的字节有效位,其中我们需要注意理解 的是  一个 数据的 最高字节及  内存的 高地址及低地址 更进一步的就算机器存储的 ...