云笔记项目-MyBatis返回自增类型&堆栈对象补充理解

时间:2021-08-29 20:01:27

在云笔记项目中,讲到了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返回自增类型&堆栈对象补充理解

映射文件中写法

由于使用了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]
}

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

云笔记项目-MyBatis返回自增类型&堆栈对象补充理解

可以看出第一次输出结果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了。参考下图:

云笔记项目-MyBatis返回自增类型&堆栈对象补充理解

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

测试内存堆栈对象-值传递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。

云笔记项目-MyBatis返回自增类型&堆栈对象补充理解

测试内存堆栈对象-值传递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,对象中的值依然是可以改变的。

云笔记项目-MyBatis返回自增类型&堆栈对象补充理解

结论

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

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

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

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