一、JVM--------Java Virtual Machine(Java虚拟机)的缩写.
大多数 JVM 将内存区域划分为 Method Area(Non-Heap)(方法区) ,Heap(堆) , Program Counter Register(程序计数器) , VM Stack(虚拟机栈,也有翻译成JAVA 方法栈的),Native Method Stack ( 本地方法栈 )
方法区用于存储JVM加载的类信息、常量、静态变量、以及编译器编译后的代码等数据
原则上讲,所有的对象都在堆区上分配内存
程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行
虚拟机栈描述的是Java方法执行的内存模型,用于存储局部变量,操作数栈,动态链接,方法出口等信息
其中Method Area 和 Heap 是线程共享的
VM Stack,Native Method Stack 和Program Counter Register 是非线程共享的。
为什么分为 线程共享和非线程共享?
首先我们熟悉一下一个一般性的 Java 程序的工作过程。一个 Java 源程序文件,会被编译为字节码文件(以 class 为扩展名),每个java程序都需要运行在自己的JVM上,然后告知 JVM 程序的运行入口,再被 JVM 通过字节码解释器加载运行。那么程序开始运行后,都是如何涉及到各内存区域的呢?
概括地说来,JVM初始运行的时候都会分配好 Method Area(方法区) 和Heap(堆) ,而JVM 每遇到一个线程,就为其分配一个 Program Counter Register(程序计数器) , VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。这也是为什么我把内存区域分为线程共享和非线程共享的原因,非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与JAVA程序运行的生命周期相同,所以这也是系统垃圾回收的场所只发生在线程共享的区域(实际上对大部分虚拟机来说知发生在Heap上)的原因。
-Xms -Xmx分别设置堆的最小值和最大值,如果要设置成堆的大小可变,那么可以将最大值和最小值设置成不一样,如果要将堆大小固定,那么只需将最大值和最小值设置成一样的就行。 jvm中分为堆和方法区 堆又进一步分为新生代和老年代 方法区为永久代 堆中区分的新生代和老年代是为了垃圾回收,新生代中的对象存活期一般不长,而老年代中的对象存活期较长,所以当垃圾回收器回收内存时,新生代中垃圾回收效果较好,会回收大量的内存,而老年代中回收效果较差,内存回收不会太多。 基于以上特性,新生代中一般采用复制算法,因为存活下来的对象是少数,所需要复制的对象少,而老年代对象存活多,不适合采用复制算法,一般是标记整理和标记清除算法。 因为复制算法需要留出一块单独的内存空间来以备垃圾回收时复制对象使用,所以将新生代分为eden区和两个survivor区,每次使用eden和一个survivor区,另一个survivor作为备用的对象复制内存区。 综上: -Xmn设置了新生代的大小为5120m,而-XXSurvivorRatio=3,所有将新生代共分成5分,eden占三份,survivor占两份,每份1/5
二 、jdbc Statement
JDBC提供了Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程
1.Statement、PreparedStatement和CallableStatement都是接口(interface)。
2.Statement继承自Wrapper、PreparedStatement继承自Statement、CallableStatement继承自PreparedStatement。
3.
Statement接口提供了执行语句和获取结果的基本方法;
PreparedStatement接口添加了处理 IN 参数的方法;
CallableStatement接口添加了处理 OUT 参数的方法。
4.
a.Statement:
普通的不带参的查询SQL;支持批量更新,批量删除;
b.PreparedStatement:
可变参数的SQL,编译一次,执行多次,效率高;
安全性好,有效防止Sql注入等问题;
支持批量更新,批量删除;
c.CallableStatement:
继承自PreparedStatement,支持带参数的SQL操作;
支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持;
Statement每次执行sql语句,数据库都要执行sql语句的编译 ,
最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。
PreparedStatement是预编译的,使用PreparedStatement有几个好处
1. 在执行可变参数的一条SQL时,PreparedStatement比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率要高。
2. 安全性好,有效防止Sql注入等问题。
3. 对于多次重复执行的语句,使用PreparedStament效率会更高一点,并且在这种情况下也比较适合使用batch;
4. 代码的可读性和可维护性。
5、一个占位符只能对应一个值。
三、Spring
事务属性的种类: 传播行为、隔离级别、只读和事务超时
a) 传播行为定义了被调用方法的事务边界。
传播行为 |
意义 |
PROPERGATION_MANDATORY |
表示方法必须运行在一个事务中,如果当前事务不存在,就抛出异常 |
PROPAGATION_NESTED |
表示如果当前事务存在,则方法应该运行在一个嵌套事务中。否则,它看起来和 PROPAGATION_REQUIRED 看起来没什么俩样 |
PROPAGATION_NEVER |
表示方法不能运行在一个事务中,否则抛出异常 |
PROPAGATION_NOT_SUPPORTED |
表示方法不能运行在一个事务中,如果当前存在一个事务,则该方法将被挂起 |
PROPAGATION_REQUIRED |
表示当前方法必须运行在一个事务中,如果当前存在一个事务,那么该方法运行在这个事务中,否则,将创建一个新的事务 |
PROPAGATION_REQUIRES_NEW |
表示当前方法必须运行在自己的事务中,如果当前存在一个事务,那么这个事务将在该方法运行期间被挂起 |
PROPAGATION_SUPPORTS |
表示当前方法不需要运行在一个是事务中,但如果有一个事务已经存在,该方法也可以运行在这个事务中 |
b) 隔离级别
在操作数据时可能带来 3 个副作用,分别是脏读、不可重复读、幻读。为了避免这 3 中副作用的发生,在标准的 SQL 语句中定义了 4 种隔离级别,分别是未提交读、已提交读、可重复读、可序列化。而在 spring 事务中提供了 5 种隔离级别来对应在 SQL 中定义的 4 种隔离级别,如下:
隔离级别 |
意义 |
ISOLATION_DEFAULT |
使用后端数据库默认的隔离级别 |
ISOLATION_READ_UNCOMMITTED |
允许读取未提交的数据(对应未提交读),可能导致脏读、不可重复读、幻读 |
ISOLATION_READ_COMMITTED |
允许在一个事务中读取另一个已经提交的事务中的数据(对应已提交读)。可以避免脏读,但是无法避免不可重复读和幻读 |
ISOLATION_REPEATABLE_READ |
一个事务不可能更新由另一个事务修改但尚未提交(回滚)的数据(对应可重复读)。可以避免脏读和不可重复读,但无法避免幻读 |
ISOLATION_SERIALIZABLE |
这种隔离级别是所有的事务都在一个执行队列中,依次顺序执行,而不是并行(对应可序列化)。可以避免脏读、不可重复读、幻读。但是这种隔离级别效率很低,因此,除非必须,否则不建议使用。 |
四、Serlvet与CGI
CGI(Common Gateway Interface),通用网关接口
通用网关接口,简称CGI,是一种根据请求信息动态产生回应内容的技术。通过CGI,Web 服务器可以将根据请求不同启动不同的外部程序,并将请求内容转发给该程序,在程序执行结束后,将执行结果作为回应返回给客户端。也就是说,对于每个请求,都要产生一个新的进程进行处理。因为每个进程都会占有很多服务器的资源和时间,这就导致服务器无法同时处理很多的并发请求。另外CGI程序都是与操作系统平台相关的,虽然在互联网爆发的初期,CGI为开发互联网应用做出了很大的贡献,但是随着技术的发展,开始逐渐衰落。
Servlet
Java Servlet要求必须运行在Web服务器当中,与Web服务器之间属于分工和互补关系。确切的说,在实际运行的时候Java Servlet与Web服务器会融为一体,如同一个程序一样运行在同一个Java虚拟机(JVM)当中。与CGI不同的是,Servlet对每个请求都是单独启动一个线程,而不是进程。这种处理方式大幅度地降低了系统里的进程数量,提高了系统的并发处理能力。另外因为Java Servlet是运行在虚拟机之上的,也就解决了跨平台问题。
为了能够输出HTML格式内容,需要编写大量重复代码,造成不必要的重复劳动。为了解决这个问题,基于Servlet技术产生了JavaServer Pages技术,也就是JSP。Servlet和JSP两者分工协作,Servlet侧重于解决运算和业务逻辑问题,JSP则侧重于解决展示问题。 Servlet与JSP一起为Web应用开发带来了巨大的贡献,后来出现的众多Java Web应用开发框架都是基于这两种技术的,更确切的说,都是基于Servlet技术的。
而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于Servlet 。
五、forward和redirect
forward和redirect是最常问的两个问题 forward,服务器获取跳转页面内容传给用户,用户地址栏不变 redirect,是服务器向用户发送转向的地址,redirect后地址栏变成新的地址六、加载驱动方法
1.Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); 2. DriverManager.registerDriver(new com.mysql.jdbc.Driver()); 3.System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver"); DriverManager.getConnection方法返回一个Connection对象,这是加载驱动之后才能进行的创建一个以JDBC连接数据库的程序,包含
7
个步骤:
1
、加载JDBC驱动程序:
在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),
这通过java.lang.Class类的静态方法forName(String className)实现。
例如:
try
{
//加载MySql的驱动类
Class.forName(
"com.mysql.jdbc.Driver"
);
}
catch
(ClassNotFoundException e)
{
System.out.println(
"找不到驱动程序类 ,加载驱动失败!"
);
e.printStackTrace();
}
成功加载后,会将Driver类的实例注册到DriverManager类中。
2
、提供JDBC连接的URL
<blockquote style=
"vertical-align: baseline;"
>
<ul style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
连接URL定义了连接数据库时的协议、子协议、数据源标识。
</li><li style=
"vertical-align: baseline;"
>
书写形式:协议:子协议:数据源标识
</li><li style=
"vertical-align: baseline;"
>
协议:在JDBC中总是以jdbc开始
</li><li style=
"vertical-align: baseline;"
>
子协议:是桥连接的驱动程序或是数据库管理系统名称。
</li><li style=
"vertical-align: baseline;"
>
数据源标识:标记找到数据库来源的地址与连接端口。
jdbc:mysql:
//localhost:3306/test?useUnicode=true&characterEncoding=gbk;
useUnicode=
true
:表示使用Unicode字符集。
如果characterEncoding设置为gb2312或GBK,本参数必须设置为
true
&characterEncoding=gbk;字符编码方式。
3
、创建数据库的连接
<blockquote style=
"vertical-align: baseline;"
>
<ul style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
要连接数据库,需要向java.sql.DriverManager请求并获得Connection对象,该对象就代表一个数据库的连接。
</li><li style=
"vertical-align: baseline;"
>
使用DriverManager的getConnectin(String url , String username , String password )方法传入指定的欲连接的数据库的路径、数据库的用户名和密码来获得。
例如:
//连接MySql数据库,用户名和密码都是root
String url =
"jdbc:mysql://localhost:3306/test"
;
String username =
"root"
;
String password =
"root"
;
try
{
Connection con = DriverManager.getConnection(url , username , password ) ;
}
catch
(SQLException se){
System.out.println(
"数据库连接失败!"
);
se.printStackTrace() ;
}
4
、创建一个Statement
<blockquote style=
"vertical-align: baseline;"
>
<ul style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
要执行SQL语句,必须获得java.sql.Statement实例,Statement实例分为以下
3
种类型:
<ol style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
执行静态SQL语句。通常通过Statement实例实现。
</li><li style=
"vertical-align: baseline;"
>
执行动态SQL语句。通常通过PreparedStatement实例实现。
</li><li style=
"vertical-align: baseline;"
>
执行数据库存储过程。通常通过CallableStatement实例实现。
具体的实现方式:
Statement stmt = con.createStatement() ;
PreparedStatement pstmt = con.prepareStatement(sql) ;
CallableStatement cstmt = con.prepareCall(
"{CALL demoSp(? , ?)}"
) ;
5
、执行SQL语句
<blockquote style=
"vertical-align: baseline;"
>
<ul style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute
<ol style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
ResultSet executeQuery(String sqlString):执行查询数据库的SQL语句,返回一个结果集(ResultSet)对象。
</li><li style=
"vertical-align: baseline;"
>
int
executeUpdate(String sqlString):用于执行INSERT、UPDATE或
DELETE语句以及SQL DDL语句,如:CREATE TABLE和DROP TABLE等
</li><li style=
"vertical-align: baseline;"
>
execute(sqlString):用于执行返回多个结果集、多个更新计数或二者组合的
语句。
ResultSet rs = stmt.executeQuery(
"SELECT * FROM ..."
) ;
int
rows = stmt.executeUpdate(
"INSERT INTO ..."
) ;
boolean
flag = stmt.execute(String sql) ;
<ul style=
"vertical-align: baseline;text-align: right;"
>
<li style=
"vertical-align: baseline;"
>
1
</li><li style=
"vertical-align: baseline;"
>
2
</li><li style=
"vertical-align: baseline;"
>
3
6
、处理结果
<blockquote style=
"vertical-align: baseline;"
>
<ul style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
两种情况:
<ol style=
"vertical-align: baseline;"
>
<li style=
"vertical-align: baseline;"
>
执行更新返回的是本次操作影响到的记录数。
</li><li style=
"vertical-align: baseline;"
>
执行查询返回的结果是一个ResultSet对象。
<ul style=
"vertical-align: baseline;color: rgb(153,153,153);"
>
<li style=
"vertical-align: baseline;"
>
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法提供了对这些
行中数据的访问。
</li><li style=
"vertical-align: baseline;"
>
使用结果集(ResultSet)对象的访问方法获取数据:
while
(rs.next()){ String name = rs.getString(
"name"
) ; String pass = rs.getString(
1
) ;
// 此方法比较高效 }
<ul style=
"vertical-align: baseline;text-align: right;"
>
<li style=
"vertical-align: baseline;"
>
1
</li><li style=
"vertical-align: baseline;"
>
2
</li><li style=
"vertical-align: baseline;"
>
3
</li><li style=
"vertical-align: baseline;"
>
4
(列是从左到右编号的,并且从列
1
开始)
7
、关闭JDBC对象
操作完成以后要把所有使用的JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声
明顺序相反:
1
、关闭记录集
2
、关闭声明
if
(rs !=
null
){
// 关闭记录集
try
{
rs.close() ;
}
catch
(SQLException e){
e.printStackTrace() ;
}
}
if
(stmt !=
null
){
// 关闭声明
try
{
stmt.close() ;
}
catch
(SQLException e){
e.printStackTrace() ;
}
}
if
(conn !=
null
){
// 关闭连接对象
try
{
conn.close() ;
}
catch
(SQLException e){
e.printStackTrace() ;
}
}
</li></ul></li></ul></li></ol></li></ul></blockquote></li></ul></li></ol></li></ul></blockquote></li></ol></li></ul></blockquote></li></ul></blockquote></li></ul></blockquote>
七、引用与内存
public
class
Square {
long
width;
public
Square(
long
l) {
width = l;
}
public
static
void
main(String arg[]) {
Square a, b, c;
a =
new
Square(42L);
b =
new
Square(42L);
c = b;
long
s = 42L;
}
}
a==b s==a b==c a.euqals(s)
这题考的是引用和内存。
//声明了3个Square类型的变量a, b, c
//在stack中分配3个内存,名字为a, b, c
Square a, b, c;
//在heap中分配了一块新内存,里边包含自己的成员变量width值为48L,然后stack中的a指向这块内存
a = new Square(42L);
//在heap中分配了一块新内存,其中包含自己的成员变量width值为48L,然后stack中的b指向这块内存
b = new Square(42L);
//stack中的c也指向b所指向的内存
c = b;
//在stack中分配了一块内存,值为42
long s = 42L;
|
1 2 3 |
public boolean equals(Object obj) {
return ( this == obj);
}
|
八、int与integer
Integer i01 =
59
;
int
i02 =
59
;
Integer i03 =Integer.valueOf(
59
);
Integer i04 =
new
Integer(
59
);
Integer i01=59 的时候,会调用 Integer 的 valueOf 方法,
1 2 3 4 5 |
public static Integer valueOf( int i) {
assert IntegerCache.high>= 127 ;
if (i >= IntegerCache.low&& i <= IntegerCache.high)
return IntegerCache.***[i+ (-IntegerCache.low)];
return new Integer(i); }
|
这个方法就是返回一个 Integer 对象,只是在返回之前,看作了一个判断,判断当前 i 的值是否在 [-128,127] 区别,且 IntegerCache 中是否存在此对象,如果存在,则直接返回引用,否则,创建一个新的对象。
在这里的话,因为程序初次运行,没有 59 ,所以,直接创建了一个新的对象。
int i02=59 ,这是一个基本类型,存储在栈中。
Integer i03 =Integer.valueOf(59); 因为 IntegerCache 中已经存在此对象,所以,直接返回引用。
Integer i04 = new Integer(59) ;直接创建一个新的对象。
System. out .println(i01== i02); i01 是 Integer 对象, i02 是 int ,这里比较的不是地址,而是值。 Integer 会自动拆箱成 int ,然后进行值的比较。所以,为真。
System. out .println(i01== i03); 因为 i03 返回的是 i01 的引用,所以,为真。
System. out .println(i03==i04); 因为 i04 是重新创建的对象,所以 i03,i04 是指向不同的对象,因此比较结果为假。
System. out .println(i02== i04); 因为 i02 是基本类型,所以此时 i04 会自动拆箱,进行值比较,所以,结果为真。
九、异常
运行时异常: 都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常): 是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。