20145215《Java程序设计》第9周学习总结
20145215《Java程序设计》第九周学习总结
教材学习内容总结
整合数据库
JDBC入门
-
JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数据库厂商则对接口进行操作,开发人员无须接触底层数据库驱动程序的差异性。
-
数据库本身是个独立运行的应用程序,你撰写的应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找。通常你的应用程序会利用一组专门与数据库进行通信协议的链接库,以简化与数据库沟通时的程序撰写。
-
我们有时需要更换数据库,应用程序跨平台也是经常的需求,JDBC基本上就是用来解决这些问题的。JDBC是Java联机数据库的标准规范。具体而言,它定义了一组标准类与接口,应用程序需要联机数据库时调用这组标准API,而标准API中的接口由数据库厂商操作,通常称为JDBC驱动程序。
-
JDBC标准主要分为两个部分:JDBC应用程序开发者接口以及JDBC驱动程序开发者接口。如果应用程序需要联机数据库,就是调用JDBC应用程序开发者接口,相关API主要在
java.sql
与javax.sql
两个包中,JDBC驱动程序开发者接口是数据库厂商操作驱动程序时的规范。
-
厂商依操作方式可将JDBC驱动程序分为四种类型:
- JDBC-ODBC Bridge Driver
- Native API Driver
- JDBC-Net Driver
- Native Protocal Driver
- 为了要连接数据库系统,必须要有厂商操作的JDBC驱动程序,必须在CLASSPATH中设定驱动程序JAR文档,关于教材中连接数据库的操作,详情请见教材学习中的问题和解决过程。
- 取得联机等与数据库来源相关的行为规范在
java.sql.DataSource
接口中,实际如何取得Connection则由操作接口的对象来负责。Connection是数据库连接的代表对象,接下来要执行SQL的话,必须取得java.sql.Statement
操作对象,它是SQL描述的代表对象。 - Statement的execute()可以用来执行SQL,并可以测试SQL是执行查询或更新,返回true表示SQL执行将返回ResultSet作为查询结果,此时可以使用getResultSet()取得ResultSet对象。视需求而定,Statement或者ResultSet在不使用时,可以使用close()将之关闭,以释放相关资源。Statement关闭时,所关联的ResultSet也会自动关闭。
- 如果有些操作只是SQL语句当中某些参数会有所不同,其余的SQL子句皆相同,则可以使用
java.sql.PreparedStatement
。可以使用Connection的PreparedStatement()方法建立好预先编译的SQL语句,当中参数会变动的部分,先指定“?”这个占位字符。 - 在JDBC里要表示日期,是使用
java.sql.Date
,其日期格式是“年、月、日”,要表示时间的话则是使用java.sql.Time
,其时间格式为“时、分、秒”,如果要表示“时、分、秒、微秒”的格式,你可以使用java.sql.Timestamp
。
JDBC进阶
- SimpleConnectionPoolDataSource操作了DataSource接口,其中使用List
实例维护可重用的Connection,联机相关信息可以使用.properties设定。 - 在ResultSet时,默认可以使用next()移动数据光标至下一笔数据,而后使用getXXX()方法来取得数据。结果集类型可以指定3种设定:ResultSet.TYPEFORWARDONLY(默认)、ResultSet.TYPESCROLLINSENSITIVE、ResultSet.TYPESCROLLSENSITIVE。更新设定可以有两种指定:ResultSet.CONCURREADONLY(默认)、ResultSet.CONCUR_UPDATABLE。
- 每一次执行executeUpdate(),其实都会向数据库发送一次SQL,如果大量更新的SQL有一万笔,就等于通过网络进行了一万次的信息传送,网络传送信息实际上必须打开I/O、进行路由等动作。所以最好就是所有收集的SQL,最后会串为一句SQL,然后传送给数据库,既然是批次更新,顾名思义,就是仅用在更新上,所以批次更新的限制是,SQL不能是SELECT,否则会抛出异常。
- 如果要将文档写入数据库,可以在数据库表格字段上使用BLOB或CLOB数据类型,BLOB用于存储大量二进制数据,像是图档、影音档等,CLOB用于存储大量的文字数据。
- 交易的四个基本要求是原子性、一致性、隔离行为与持续性。当多个交易并行时,可能引发的数据不一致问题:
- 更新遗失:基本上就是指某个交易对字段进行更新的信息,因另一个交易的介入而遗失更新效力。
- 脏读:两个交易同时进行时,其中一个交易更新数据但未确认,另一个交易就读取数据,就有可能发生脏读问题。
- 无法重复的读取:某个交易两次读取同一字段的数据并不一致。
- 幻读:同一交易期间,读取到的数据笔数不一致。
- JDBC定义了java.sql.RowSet接口,用以代表数据的列集合,这里的数据并不一定是数据库中的数据,可以是电子表格数据、XML数据或任何具有列集合概念的数据源。RowSet定义了列集合基本行为,其下有JdbcRowSet、CachedRowSet、FilteredRowSet、JoinRowSet、WebRowSet五个标准列集合子接口,定义在
javax.sql.rowset
包中。
反射与类加载器
运用反射
- Java真正需要某个类时才会载入对应的.class文档,
java.lang.Class
的实例代表Java应用程序运行时载入的.class文档,Class类没有公开(public)构造函数,实例是由JVM自动产生,可以通过Object的getClass()方法,或者是透过.class常量取得每个对象对应的Class对象。 - 可以使用Class.forName()方法实现动态加载类,Class.forName()方法在找不到指定类时会抛出
ClassNotFoundException
异常。 - Class对象加载的.class文档,取得Class对象后,就可以取得.class文档中记载的信息,每个类型都会有对应的类型,如果事先不知道类名称,可以利用Class.forName()动态加载.class文档,取得Class对象之后,利用其newInstance()方法建立类实例。
了解类加载器
- 类加载指的是将类的class文件读入JVM,并为之创建一个Class对象。
- JVM预定义的三种类型类加载器,当一个JVM启动的时候,开始使用如下三种类型类装入器:
- 启动(Bootstrap)类加载器:引导类装入器是用本地代码实现的类装入器,它负责将 <Java_Runtime_Home>/lib下面的核心类库或-Xbootclasspath选项指定的jar包加载到内存中。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。
- 扩展(Extension)类加载器:扩展类加载器是由Sun的ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将< Java_Runtime_Home >/lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
- 系统(System)类加载器:系统类加载器是由 Sun的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的。它负责将系统类路径java -classpath或-Djava.class.path变量所指的目录下的类库加载到内存中。开发者可以直接使用系统类加载器。
- Bootstrap Loader、Extended Loader与System Loader在程序启动后,就无法再改变它们的搜索路径。如果在程序运行过程中,打算动态决定从其他路径加载类,就要产生新的类加载器,新的类加载器建立后,父加载器会设为System Loader。
自定义泛型、枚举与注释
自定义泛型
- 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在调用时传入具体的类型(类型实参)。
- 泛型也可以仅定义在方法上,可在方法返回类型前使用
定义泛型,之后就可以使用T来定义返回类型、参数类型,或在方法内声明变量、转换类型等,在定义泛型时,使用extends限制指定T实际类型时,必须是某类的子类。 - 如果B是A的子类,而Node(B)可视为一种Node(A),则称Node具有逆变性。Java泛型并不支持逆变性,可以使用类型通配字符?与super来声明,以达到类似逆变性的效果。
自定义枚举
- 创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum<E extends Enum
>,而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。 - 定义enum时可以自定义构造函数,条件是不得为公开(public)构造函数,也不可以在构造函数中调用super(),定义enum时有个特定值类本体语法,可用于操作接口或重新定义父类方法。
注释
- Java提供了一些标准注释,我们经常看到的@Override就是标准注释。举个例子来说,现在有Son和Parent两个类,且类型Son将会重写类型Parent的getName函数,但是由于我们的马虎,一不小心写成了下面的代码:
public class Parent{
public String getName(){
return "Parent";
}
}
public class Son extends Parent{
public String getNames(){
return "Son";
}
}
当我们用上@Override注释时,就不会再发生这样的问题,子类函数添加 @Override 后,该函数重写父类中签名相同的函数,否则将会编译失败。
- 默认会将注释信息存储于.class文档,可被编译程序或位码分析工具读取,但执行时期无法读取注释信息,在执行时期读取注释信息,可以使用java.lang.annotation.Retention搭配java.lang.annotation.RetentionPolicy枚举指定。 RetentionPolicy为RUNTIME的时机,在于让注释在执行时期提供应用程序信息,可使用java.lang.reflect.AnnotatedElement接口操作对象取得注释信息。 JDK 8中新增了getDeclaredAnnotation()、getDeclaredAnnotationsByType()、getAnnotationsByType()三个方法。 getDeclaredAnnotation()可以让你取回指定的标注,在指定@Repeatable的标注时,会寻找收集重复标注的容器。 getDeclaredAnnotationsByType()、getAnnotationsByType()就不会处理@Repeatable的标记。
教材学习中的问题和解决过程
- 关于教材509页ConnectionDemo.java代码进行数据库联机:
-
一开始运行代码,发现抛出异常:
-
这是因为没有导入MySQL的驱动包,因此我们先需要下载MySQL JDBC,这里给大家提供一个下载地址
-
进入下载页面之后找到
JDBC Driver for MySQL
,点击Download
-
接着选择下面那个,即下载ZIP压缩包
-
直接下载即可
-
下载完成之后解压,将
mysql-connector-java-5.1.38-bin.jar
放到你的JDK中lib目录下 -
接着,在IDEA中导入这个jar包,选中External Libraries< 1.8 >,然后右键打开
Open Library Settings
-
点击右边的绿色"+",找到
mysql-connector-java-5.1.38-bin.jar
添加进来
-
这时,再次运行程序会发现抛出了新的异常,这是因为我们还没有安装MySQL,数据库自然也就无法联机了
-
先下载娄老师上传到QQ群里的XAMPP,这是一个集Apache、MySQL、PHP、PERL为一体的功能强大的建站集成软件包,下载完成之后解压,然后双击
setup_xampp.bat
进行配置,这样能使配置文件中的路径信息得到更新。 -
接着打开
xampp-control.exe
,点击start打开MySQL
-
一开始我本来想点击admin,直接创建数据库,但是点开之后发现无法访问网页
-
于是,只好点开Shell命令窗口,先输入指令
mysql -uroot
(ps:由于我的代码中没有设密码,因此,在这里输入指令时也不需要输入密码,如果有密码的话可以用指令mysql -uroot -p
)
-
为了防止出现乱码问题,我们还要设置数据库使用UTF-8进行编码,于是输入指令
SET NAMES utf8;
-
然后输入指令
CREATE DATABASE lesson
,创建数据库
-
这时再运行程序,便能成功开启数据库联机
在此大家可以参考一下常见的MySQL数据库命令
心得体会
本周学习的重点在于MySQL的学习,刚刚接触的时候感觉有点无从下手,中间花了比较长的时间去摸索XAMPP软件,后来通过在网上搜集资料慢慢对XAMPP有所了解,并且建立起了一个简单的数据库。一开始我想不太明白Java和数据库之间到底有什么联系,但是我慢慢意识到Java应用的主流应该是在网络方向,尤其是大规模的企业级应用,这必然导致要与大批量的数据发生关系,因此用数据库来对这些数据进行管理对于一些用Java开发的大规模应用来说是非常有必要的,这也就更加说明了数据库对Java的重要性,如果我们能够学好数据库,那么对于今后一些项目的开发也会非常有帮助。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | 编写了Hello Java代码 |
第一周 | 100/100 | 2/2 | 12/12 | 编写了Hello Java代码 |
第二周 | 200/300 | 2/4 | 15/27 | 理解了printf和println的区别 |
第三周 | 450/750 | 1/5 | 22/49 | 对对象有了更深层次的理解 |
第四周 | 869/1619 | 1/6 | 28/77 | 对对象的三大特征有了更全面的认识 |
第五周 | 1123/2742 | 1/7 | 25/102 | 学会了异常处理 |
第六周 | 863/3605 | 2/9 | 30/132 | 理解了线程 |
第七周 | 505/4110 | 2/11 | 28/160 | 掌握了日期和时间的运用 |
第八周 | 490/4600 | 2/13 | 26/186 | 掌握了git托管的节奏 |
第九周 | 591/5191 | 2/15 | 30/216 | 初步学会使用MySQL |
【附1】本周学习的代码已经成功托管,截图如下:
【附2】利用wc统计代码行数,截图如下: