zoukankan      html  css  js  c++  java
  • 云笔记项目-MyBatis返回自增类型&堆栈对象补充理解

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

    MySql数据类型自增

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

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

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

    映射文件中写法

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

    1    <insert id="addPerson" parameterType="com.boe.Entity.Person" useGeneratedKeys="true" keyProperty="id">
    2       insert into
    3       p_person
    4       values(
    5       #{id},
    6       #{name}
    7       )
    8    </insert>

    使用Spring容器插入数据

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

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

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

    可以看出第一次输出结果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。

     1     //再次测试内存堆栈,对象
     2     @Test
     3     public void test1() {
     4         String s="A";
     5         StringBuilder sb=new StringBuilder("A");
     6         add(s,sb);
     7         //输出
     8         System.out.println(s);//A
     9         System.out.println(sb);//AA
    10     }
    11     
    12     /**
    13      * 测试方法,传入一个String类型和StringBuilder类型
    14      * @param s
    15      * @param sb
    16      */
    17     public static void add(String s,StringBuilder sb) {
    18         s=s+"A";
    19         sb.append("A");
    20     }

    可以参考上面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。

     1     //再次测试内存堆栈,对象
     2     @Test
     3     public void test2() {
     4         Integer i=2;//Integer包装类跟String类型,也是final修饰的,是不可变量
     5         int[] array= {2}; 
     6         doSome(i,array);
     7         //输出执行完后结果
     8         System.out.println(i);//2
     9         System.out.println(array[0]);//3
    10     }
    11     
    12     /**
    13      * 测试方法,传入Integer包装类和int数组
    14      * @param i
    15      * @param array
    16      */
    17     public static void doSome(Integer i,int[] array) {
    18         i=i++;
    19         array[0]++;
    20     }

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

    与上面的原因类似,由于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

  • 相关阅读:
    excel文件导入mysql
    linux进程后台运行,且关终端后继续运行
    安装windows后grub修复
    华中科技大学 ubuntu14.04源
    Windows8.1远程桌面时提示凭据不工作的解决方案
    引文分析工具HistCite使用简介
    报账单打印
    iOS开发之--复制粘贴功能
    iOS学习之--字符串的删除替换(字符串的常用处理,删除,替换)
    iOS 裁剪View指定的角裁剪
  • 原文地址:https://www.cnblogs.com/youngchaolin/p/10780571.html
Copyright © 2011-2022 走看看