找工作复习2
PS:
java规定如果两个对象equals返回true,那么这两个对象的hashCode码必须一致。
PS: 事务的四种隔离级别
事务的特性:
原子性,是一个最小逻辑操作单元 !
一致性,事务过程中,数据处于一致状态。
持久性, 事务一旦提交成功,对数据的更改会反映到数据库中。
隔离性, 事务与事务之间是隔离的。
PS:
----------------------------------------------------------
单例模式
http://blog.csdn.net/abc19900828/article/details/39479377
classpath环境变量
- classpath的作用: 作用是指定类搜索路径,要使用已经编写好的类,前提当然是能够找到它们了,一旦配置了classpath路径信息的时候,jvm与java编译器都会根据classpath指定的路径去寻找class文件。
==========================================
逻辑运算
“&”和“&&”的区别:单与时,左边无论真假,右边都进行运算;双与时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
=========================================
PS:”&”、“|”、“^”除了可以作为逻辑运算符也可以作为位运算符。
----------------------------运算符的优先级-----------------------
/*判断闰年,能被4整除,不能被400整除,或能被400整除的*/ private static boolean getResult(int year) { // TODO Auto-generated method stub if((year%4==0&&year%100!=0)||year%400==0){ return true; } return false; }
==================生成指定区间的随机数=======================
nextInt(4)将产生0,1,2,3这4个数字中的任何一个数字,注意这里不是0-4,而是0-3。
int MAX = 40; int MIN = 30; Random random = new Random(); System.out.println(random.nextInt(MAX-MIN+1)+MIN);
=================构造代码块===========================================
1:给对象进行初始化。对象一建立就运行并且优先于构造函数。
作用
1:给对象进行初始化。对象一建立就运行并且优先于构造函数。
2:与构造函数区别
1:构造代码块和构造函数的区别,构造代码块是给所有对象进行统一初始化, 构造函数给对应的对象初始化。
2:构造代码块的作用:它的作用就是将所有构造方法中公共的信息进行抽取。
例如孩子一出生统一哭
==================this==========================================
PS:this只能在非静态中(没有static修饰的)函数使用
this是什么
1:在构造函数中打印this
2:创建对象,打印对象名p
3:this和p是一样的都是内存地址值。//p是对象的引用
4:this代表所在函数所属对象的引用
=====================重写=======================================
1: 函数名必须相同
2:参数列表必须相同
3: 子类重写父类的函数的时候,函数的访问权限必须大于等于父类的函数的访
问权限否则编译报错
4:子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类。不能返回比父类更大的数据类型: 如子类函数返回值类型是Object
======================继承=========================
为什么子类一定要访问父类的构造函数呢
1:子类继承了父类的属性,如果要使用父类的属性必须初始化,创建子类对象,必须先初始化父类属性
必须调用父类的构造方法。
2:为什么调用父类无参的构造函数
设计java语言之时,只知道编译器会默认添加无参的构造函数,有参的无法确定。
但是可以通过super关键字显式调用父类指定构造函数。
3:为什么super()this()语句要放在构造函数的第一行
子类可能会用到父类的属性,所以必须先初始化父类。
======================构造函数=========================
Demo类被加载,执行main方法,Son.class加载,发现有父类Father类,于是Father类也加载进内存。类加载完毕,创建对象,父类的构造方法会被调用(默认自动无参),
如果父类没有无参,则报错
============API
PS1:
StringBuffer : 由于String是不可变的,所以导致String对象泛滥,在频繁改变字符串对象的应用中,需要使用可变的字符串缓冲区类。
- 默认缓冲区的容量是16。
==========
1.1 线程的状态
创建:新创建了一个线程对象。
可运行:线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取cpu的执行权。
运行:就绪状态的线程获取了CPU执行权,执行程序代码。
阻临时塞: 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
死亡:线程执行完它的任务时。
============后台线程=================
当所有的非后台线程结束时,程序也就终止了同时还会杀死进程中的所有后台线程,也就是说,只要有非后台线程还在运行,程序就不会终止,执行main方法的主线程就是一个非后台线程。
=============ArrayList=================
PS: ArrayList 底层采用数组实现,默认10。每次增长60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。
============Collections================
1.对list集合中的元素进行位置的置换。
swap(list,x,y);
=======================Arrays------------------------
2. 复制数组。
copyOf();
1, 复制部分数组。
copyOfRange():
2, 比较两个数组是否相同。
equals(int[],int[]);
==============Hashset存储元素==================
HashSet到底是如何判断两个元素重复。
通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型
判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。
=====================
Set<Map.Entry<K,V>> entrySet()
面向对象的思想将map集合中的键和值映射关系打包为一个对象,就是Map.Entry
,将该对象存入Set集合,Map.Entry是一个对象,那么该对象具备的getKey,getValue获得键和值。
================List的set方法,交换两个对象的值=============================
import java.util.ArrayList; import java.util.LinkedList; import java.util.Random; /* 需求: 使用LinkedList存储一副扑克牌,然后实现洗牌功能。 */ //扑克类 class Poker{ String color; //花色 String num; //点数 public Poker(String color, String num) { super(); this.color = color; this.num = num; } @Override public String toString() { return "{"+color+num+"}"; } } public class Demo2 { public static void main(String[] args) { ArrayList list = new ArrayList(); //list. LinkedList pokers = createPoker(); shufflePoker(pokers); showPoker(pokers); } //洗牌的功能 public static void shufflePoker(LinkedList pokers){ //创建随机数对象 Random random = new Random(); for(int i = 0 ; i <100; i++){ //随机产生两个索引值 int index1 = random.nextInt(pokers.size()); int index2 = random.nextInt(pokers.size()); //根据索引值取出两张牌,然后交换两张牌的顺序 Poker poker1 = (Poker) pokers.get(index1); Poker poker2 = (Poker) pokers.get(index2); pokers.set(index1, poker2); pokers.set(index2, poker1); } } //显示扑克牌 public static void showPoker(LinkedList pokers){ for(int i = 0 ; i<pokers.size() ; i++){ System.out.print(pokers.get(i)); //换行 if(i%10==9){ System.out.println(); } } } //生成扑克牌的方法 public static LinkedList createPoker(){ //该集合用于存储扑克对象。 LinkedList list = new LinkedList(); //定义数组存储所有的花色与点数 String[] colors = {"黑桃","红桃","梅花","方块"}; String[] nums = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"}; for(int i = 0 ; i < nums.length ; i++){ for(int j = 0 ; j<colors.length ; j++){ list.add(new Poker(colors[j], nums[i])); } } return list; } }
====================正则表达式=================================
PS:功能主要有四个:
1.匹配,
public static void checkQQ2() { String qq = "12345"; String reg = "[1-9][0-9]{4,14}"; boolean b = qq.matches(reg); System.out.println("b="+b); }
2.切割,split()
3.替换,
String str = "联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119"; String reg= "1[34578]\\d{9}"; str = str.replaceAll(reg,"******"); System.out.println("替换后的帖子
String str = "联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119"; String regex = "联系我"; str = str.replaceAll(regex , "zhh"); System.out.println(str);//zhh:13567012119zhh:13567012119zhh:13567012119zhh:13567012119zhh:13567012119zhh:13567012119
4.获取,
public static void getDemo() { String str = "da jia zhu yi le,ming tian bu fang jia,xie xie!"; //想要获取由3个字母组成的单词。 //刚才的功能返回的都是一个结果,只有split返回的是数组,但是它是把规则作为分隔符,不会获取符合规则的内容。 //这时我们要用到一些正则对象。 String reg = "\\b[a-z]{3}\\b"; Pattern p = Pattern.compile(reg); Matcher m = p.matcher(str); while(m.find()) { System.out.println(m.start()+"...."+m.end()); System.out.println("sub:"+str.substring(m.start(),m.end())); System.out.println(m.group()); } // System.out.println(m.find());//将规则对字符串进行匹配查找。 // System.out.println(m.find());//将规则对字符串进行匹配查找。 // System.out.println(m.group());//在使用group方法之前,必须要先找,找到了才可以取。 }
http://www.cnblogs.com/ggjucheng/p/3423731.html 看正则
=============路径分隔符================
PS:在Windows中分隔符为 '\',在Unix/Linux中分隔符为 '/'
==================流======================
PS: 读文件流
PS: 在创建文件的时候追加。
// 1:打开文件输出流,流的目的地是指定的文件
FileOutputStream fos = new FileOutputStream(path,true);
// 2.复制文件
public static void copyFile2(String srcPath, String destPath) throws IOException { // 打开输入流,输出流 FileInputStream fis = new FileInputStream(srcPath); FileOutputStream fos = new FileOutputStream(destPath); // 读取和写入信息 int len = 0; // 使用字节数组,当做缓冲区 byte[] byt = new byte[1024]; while ((len = fis.read(byt)) != -1) { fos.write(byt, 0, len); } // 关闭流 fis.close(); fos.close(); }
PS:其实就是就是在fis和fos提供的缓冲流
上述程序中我们为了提高流的使用效率,自定义了字节数组,作为缓冲区.Java其实提供了专门的字节流缓冲来提高效率.
BufferedInputStream和BufferedOutputStream
BufferedOutputStream和BufferedOutputStream类可以通过减少读写次数来提高输入和输出的速度。它们内部有一个缓冲区,用来提高处理效率。查看API文档,发现可以指定缓冲区的大小。其实内部也是封装了字节数组。没有指定缓冲区大小,默认的字节是8192。
显然缓冲区输入流和缓冲区输出流要配合使用。首先缓冲区输入流会将读取到的数据读入缓冲区,当缓冲区满时,或者调用flush方法,缓冲输出流会将数据写出。
注意:当然使用缓冲流来进行提高效率时,对于小文件可能看不到性能的提升。但是文件稍微大一些的话,就可以看到实质的性能提升了。
=========编码和解码===================
PS:字符流的出现是因为,字节流再处理非字节流时字符的信息不太方便。(char)
字符流 = 字节流 + 编码(解码) 主要是为了保存文本文件
PS:字符流的copy
public static void main(String[] args) throws Exception { String path1 = "c:/a.txt"; String path2 = "c:/b.txt"; copyFile(path1, path2); } public static void copyFile3(String path1, String path2) throws Exception { Reader reader = new FileReader(path1); Writer writer = new FileWriter(path2); int ch = -1; char [] arr=new char[1024]; while ((ch = reader.read(arr)) != -1) { writer.write(arr,0,ch); } reader.close(); writer.close(); }
PS:字符缓冲流是为了 char 【】 的原因, 使用装饰者模式,可以整行整行的读
public class Demo7 { public static void main(String[] args) throws IOException { // 关联源文件 File srcFile = new File("c:\\linux大纲.txt"); // 关联目标文件 File destFile = new File("d:\\linux大纲.txt"); // 实现拷贝 copyFile(srcFile, destFile); } private static void copyFile(File srcFile, File destFile) throws IOException { // 创建字符输入流 FileReader fr = new FileReader(srcFile); // 创建字符输出流 FileWriter fw = new FileWriter(destFile); // 字符输入流的缓冲流 BufferedReader br = new BufferedReader(fr); // 字符输出流的缓冲流 BufferedWriter bw = new BufferedWriter(fw); String line = null; // 一次读取一行 while ((line = br.readLine()) != null) { // 一次写出一行. bw.write(line); // 刷新缓冲 bw.flush(); // 进行换行,由于readLine方法默认没有换行.需要手动换行 bw.newLine(); } // 关闭流 br.close(); bw.close(); } }
==============其他流============
1.1.2 由于上述ObjectOutput和ObjectInput是接口,所以需要使用具体实现类。
PS:主要是用来序列化对象的
ObjectOutput ObjectOutputStream被写入的对象必须实现一个接口:Serializable 否则会抛出:NotSerializableException ObjectInput ObjectInputStream 该方法抛出异常:ClassNotFountException |
ObjectOutputStream和ObjectInputStream 对象分别需要字节输出流和字节输入流对象来构建对象。也就是这两个流对象需要操作已有对象将对象进行本地持久化存储。
1.1.1. SequenceInputStream 序列流,对多个流进行合并。
序列化和反序列化Cat对象。 public class Demo3 { public static void main(String[] args) throws IOException, ClassNotFoundException { Cat cat = new Cat("tom", 3); FileOutputStream fos = new FileOutputStream(new File("c:\\Cat.txt")); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(cat); System.out.println(cat); oos.close(); // 反序列化 FileInputStream fis = new FileInputStream(new File("c:\\Cat.txt")); ObjectInputStream ois = new ObjectInputStream(fis); Object readObject = ois.readObject(); Cat cat2 = (Cat) readObject; System.out.println(cat2); fis.close(); } class Cat implements Serializable { public String name; public int age; public Cat() { } public Cat(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Cat [name=" + name + ", age=" + age + "]"; } }
注意:序列化不适用于静态变量,因为静态变量并不属于对象的实例变量的一部分。静态变量随着类的加载而加载,是类变量。由于序列化只适用于对象。
基本数据类型可以被序列化
1.1.3 打印流
注意: 打印流的三种方法
void print(数据类型 变量)
println(数据类型 变量)
printf(String format, Object... args)
可以自定数据格式
print 和println方法的区别在于,一个换行一个不换行
print 方法和write方法的却别在于,print提供自动刷新.
普通的write方法需要调用flush或者close方法才可以看到数据.
JDK1.5之后Java对PrintStream进行了扩展,增加了格式化输出方式,可以使用printf()重载方法直接格式化输出。但是在格式化输出的时候需要指定输出的数据类型格式。
1.1.1. PrintWriter
是一个字符打印流。构造函数可以接收四种类型的值。
1,字符串路径。
2,File对象。
对于1,2类型的数据,还可以指定编码表。也就是字符集。
3,OutputStream
4,Writer
对于3,4类型的数据,可以指定自动刷新。
注意:该自动刷新值为true时,只有三个方法可以用:println,printf,format.
如果想要既有自动刷新,又可执行编码。如何完成流对象的包装?
PrintWrter pw =
new PrintWriter(new OutputSteamWriter(new FileOutputStream("a.txt"),"utf-8"),true);
如果想要提高效率。还要使用打印方法。
PrintWrter pw =
newPrintWriter(new BufferdWriter(new OutputSteamWriter(
newFileOutputStream("a.txt"),"utf-8")),true);
1.1.1. DataInputStream 重要 根据不同的数据类型进行数据的保存
以及DataOutputStream
查看API文档DataInputStream的信息。发现从底层输入流中读取基本 Java 数据类型。查看方法,有读一个字节,读一个char读一个double 的方法,
DataInputStream 从数据流读取字节,并将它们转换为正确的基本数据类型值或字符串。
该流有操作基本数据类型的方法.
有读的,那么必定有对应的写的就是DataOutputStream 将基本类型的值或字符串转换为字节,并且将字节输出到数据流。
DataInputStream类继承FilterInputStream类,并实现了DataInput接口。DataOutputStream
类继承FilterOutputStream 并实现了DataOutput 接口。
例如:
DataInputStream 操作基本数据类型的方法: int readInt():一次读取四个字节,并将其转成int值。 boolean readBoolean():一次读取一个字节。 short readShort(); long readLong(); 剩下的数据类型一样。 String readUTF():按照utf-8修改版读取字符。注意,它只能读writeUTF()写入的字符数据。 DataOutputStream DataOutputStream(OutputStream): 操作基本数据类型的方法: writeInt(int):一次写入四个字节。 注意和write(int)不同。write(int)只将该整数的最低一个8位写入。剩余三个8位丢弃。 writeBoolean(boolean); writeShort(short); writeLong(long); 剩下是数据类型也也一样。 writeUTF(String):按照utf-8修改版将字符数据进行存储。只能通过readUTF读取。 |
测试: DataOutputStream
使用DataOutputStream写数据文件。
public static void testDataInputStream() throws Exception { DataOutputStream out = new DataOutputStream(new FileOutputStream( "c:/a.txt"));
out.writeBoolean(true); out.writeByte(15); // 0x05 1 个字节 out.writeBytes("abc"); // 0x 0041 2个字节 out.writeChar('X'); // ?? out.writeChars("xyz"); out.writeLong(111); out.writeUTF("中国");
out.close();
DataInputStream in = new DataInputStream( new FileInputStream("c:/a.txt")); System.out.println(in.readBoolean()); System.out.println(in.readByte());
System.out.println(in.readByte()); System.out.println(in.readByte()); System.out.println(in.readByte());
System.out.println(in.readChar());
System.out.println(in.readChar()); System.out.println(in.readChar()); System.out.println(in.readChar());
System.out.println(in.readLong());
System.out.println(in.readUTF()); in.close(); } |
==========================
计算机中存储的都是二进制,但是要显示的时候,就是我们看到的却可以有中国 ,a 1 等字符
计算机中是没有存储字符的,但是我们却看到了。计算机在存储这些信息的时候,根据一个有规则的编号,当用户输入a 有a对映的编号,就将这个编号存进计算机中这就是编码。
PS:每个字符都有 相应的 码表,字符都保存在字节保存。有码表才能看见这么多东西。
1.1. 编码:
字符串---》字节数组
String类的getBytes() 方法进行编码,将字符串,转为对映的二进制,并且这个方法可以指定编码表。如果没有指定码表,该方法会使用操作系统默认码表。
注意:中国大陆的Windows系统上默认的编码一般为GBK。在Java程序中可以使用System.getProperty("file.encoding")方式得到当前的默认编码。
1.2. 解码:
字节数组---》字符串
String类的构造函数完成。
String(byte[] bytes) 使用系统默认码表
String(byte[],charset)指定码表
注意:我们使用什么字符集(码表)进行编码,就应该使用什么字符集进行解码,否则很有可能出现乱码(兼容字符集不会)。
// 编码操作与解码操作。 public static void main(String[] args) throws Exception { String value = System.getProperty("file.encoding"); System.out.println("系统默认的编码为 " + value); String str = "中"; // 编码操作 byte[] bytes = str.getBytes(); byte[] bytes2 = str.getBytes("gbk");// d6d0 byte[] bytes3 = str.getBytes("utf-8");// e4b8ad System.out.println(Arrays.toString(bytes)); // [-42, -48] System.out.println(Arrays.toString(bytes2));// [-42, -48] System.out.println(Arrays.toString(bytes3));// [-28, -72, -83] // 解码操作 // 编码gbk,解码utf-8乱码。 String str2 = new String(bytes2, "utf-8"); System.out.println(str2); // 编码utf-8 解码gbk,乱码 str2 = new String(bytes3, "gbk"); System.out.println(str2); // gbk兼容gb2312所以,没有问题。 str = new String("中国".getBytes("gb2312"), "gbk"); System.out.println(str); }
==============Socket编程(网络编程)===============
网络通讯的三要素:
1. IP
2. 端口号。
3. 协议.
-------------------------------
IP地址的分类:
A类地址 = 一个网络号 + 三个主机号 2^24 政府单位
B类地址 = 两个网络号+ 两个主机号 2^16 事业单位(学校、银行..)
C类地址= 三个网络号+ 一个主机号 2^8 私人使用..
-----------------------------------
PS:Socket就是IP和 端口描述
UDP通讯协议的特点:
1. 将数据极封装为数据包,面向无连接。
2. 每个数据包大小限制在64K中
3.因为无连接,所以不可靠
4. 因为不需要建立连接,所以速度快
5.udp 通讯是不分服务端与客户端的,只分发送端与接收端。
TCP通讯协议特点:
1. tcp是基于IO流进行数据 的传输 的,面向连接。
2. tcp进行数据传输的时候是没有大小限制的。
3. tcp是面向连接,通过三次握手的机制保证数据的完整性。 可靠协议。
4. tcp是面向连接的,所以速度慢。
5. tcp是区分客户端与服务端 的。
package cn.itcast.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.Socket; /* 2. 实现登陆与注册 功能。 客户端与服务端连接的时候,就要提示客户端请选择功能。 客户端注册的时候,用户名与密码都是发送给服务端 的,服务端需要把数据保存到服务端的文件上。 登陆: 登陆的时候客户端输入用户名与密码发送给服务端,服务端需要校验,返回结果给客户端。 */ public class LoginClinet { public static void main(String[] args) throws IOException { Socket socket = new Socket(InetAddress.getLocalHost(),9090); //获取socket的输出流对象 OutputStreamWriter socketOut = new OutputStreamWriter(socket.getOutputStream()); //获取到socket的输入流对象 BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); //获取到键盘的输入流对象 BufferedReader keyReader = new BufferedReader(new InputStreamReader(System.in)); while(true){ System.out.println("请选择功能: A(登陆) B(注册)"); String option = keyReader.readLine(); if("a".equalsIgnoreCase(option)){ getInfo(socketOut, keyReader, option); //读取服务器反馈的信息 String line = socketReader.readLine(); System.out.println(line); }else if("b".equalsIgnoreCase(option)){ getInfo(socketOut, keyReader, option); //读取服务器反馈的信息 String line = socketReader.readLine(); System.out.println(line); } } } public static void getInfo(OutputStreamWriter socketOut,BufferedReader keyReader, String option) throws IOException { System.out.println("请输入用户名:"); String userName = keyReader.readLine(); System.out.println("请输入密码:"); String password = keyReader.readLine(); String info = option +" "+userName+" "+password+"\r\n"; socketOut.write(info); socketOut.flush(); } }
package cn.itcast.tcp; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Properties; public class LoginServer extends Thread { Socket socket; static File file = new File("F:\\users.properties"); public LoginServer(Socket socket) { this.socket = socket; } static { try { if (!file.exists()) { file.createNewFile(); } } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { while(true){ try { // 获取socket的输入流对象 BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(socket.getInputStream())); // 获取socket的输出流对象 OutputStreamWriter socketOut = new OutputStreamWriter( socket.getOutputStream()); // 读取客户端输入的信息 String info = bufferedReader.readLine(); String[] datas = info.split(" "); // 获取到用户 的选择功能 String option = datas[0]; // 注册 String userName = datas[1]; String password = datas[2]; if ("a".equalsIgnoreCase(option)) { // 登陆 Properties properties = new Properties(); // 加载配置文件 properties.load(new FileReader(file)); if (properties.containsKey(userName)) { String tempPass = properties.getProperty(userName); if (password.equals(tempPass)) { socketOut.write("欢迎" + userName + "登陆成功\r\n"); } else { socketOut.write("密码错误\r\n"); } } else { socketOut.write("用户名不存在,请重新输入...\r\n"); } socketOut.flush(); } else if ("b".equalsIgnoreCase(option)) { // 创建一个配置文件类 Properties properties = new Properties(); //加载原来的配置文件 properties.load(new FileReader(file)); if (!properties.containsKey(userName)) { // 不存在该用户名 properties.setProperty(userName, password); // 生成一个配置文件 properties.store(new FileWriter(file), "users"); socketOut.write("注册成功..\r\n"); } else { // 存在用户名 socketOut.write("用户名已经被注册,请重新输入\r\n"); } socketOut.flush(); } } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(9090); while (true) { Socket socket = serverSocket.accept(); new LoginServer(socket).start(); } } }
=================静态代码块==============================================
静态代码块:
静态代码块是静态代码块所属的类被加载到内存的时候执行的。
静态代码块的应用场景: 以后主要用于准备一个项目的初始化工作。
比如: 从配置配置文件中读取数据库用户名与密码。
=====================对象的拷贝===========================
2 对象拷贝 2.1 对象的浅拷贝 浅复制(浅克隆)被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用仍然只指向原来的对象,换言之,浅复制仅仅复制锁考虑的对象,而不复制它所引用的对象。 public class Student implements Cloneable{ String name; int age; Student(String name,int age){ this.name=name; this.age=age; } public Object clone(){ Object o =null; try{ o=super.clone();//Object中的clone()识别出你要复制的哪一个对象 } catch(CloneNotSupportedException e){ System.out.println(e.toString()); } return o; } public static void main(String[] args){ Student s1 = new Student("zhang",18); Student s2 = (Student)s1.clone(); s2.name="li"; s2.age=20; System.out.println("name="+s1.name+","+"age="+s1.age);//修改学生2后不影响学生1的值 } } 2.2 对象深拷贝 深复制(深克隆)被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向被复制过的新对象,而不再试原有的那些被引用的对象,换言之,深复制把要复制的对象所引用的对象都复制了一遍。 把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做“解冻”或者“回鲜(depicking)”过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。 在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。 public Object deepClone() { //将对象写到流里 ByteArrayOutoutStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo=new ObjectOutputStream(bo); oo.writeObject(this); //从流里读出来 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi=new ObjectInputStream(bi); return(oi.readObject()); }
====================默认值==============================================
PS:成员变量有默认值,而局部变量没有默认值
===================Mysql======================================
1. select * from student where sage is null;
===============存储过程======================
存储过程特点
1)执行效率非常快!存储过程是在数据库的服务器端执行的!!!
2)移植性很差!不同数据库的存储过程是不能移植。
DELIMITER $ -- 声明存储过程的结束符 CREATE PROCEDURE pro_test() --存储过程名称(参数列表) BEGIN -- 开始 -- 可以写多个sql语句; -- sql语句+流程控制 SELECT * FROM employee; END $ -- 结束 结束符 -- 执行存储过程 CALL pro_test(); -- CALL 存储过程名称(参数);
参数:
IN: 表示输入参数,可以携带数据带存储过程中
OUT: 表示输出参数,可以从存储过程中返回结果
INOUT: 表示输入输出参数,既可以输入功能,也可以输出功能
PS: SQL
为什么要优化: 随着实际项目的启动,数据库经过一段时间的运行,最初的数据库设置,会与实际数据库运行性能会有一些差异,这时我们 就需要做一个优化调整。 数据库优化这个课题较大,可分为四大类: 》主机性能 》内存使用性能 》网络传输性能 》SQL语句执行性能【软件工程师】 下面列出一些数据库SQL优化方案: (01)选择最有效率的表名顺序(笔试常考) 数据库的解析器按照从右到左的顺序处理FROM子句中的表名, FROM子句中写在最后的表将被最先处理, 在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表放在最后, 如果有3个以上的表连接查询,那就需要选择那个被其他表所引用的表放在最后。 例如:查询员工的编号,姓名,工资,工资等级,部门名 select emp.empno,emp.ename,emp.sal,salgrade.grade,dept.dname from salgrade,dept,emp where (emp.deptno = dept.deptno) and (emp.sal between salgrade.losal and salgrade.hisal) 1)如果三个表是完全无关系的话,将记录和列名最少的表,写在最后,然后依次类推 2)如果三个表是有关系的话,将引用最多的表,放在最后,然后依次类推 (02)WHERE子句中的连接顺序(笔试常考) 数据库采用自右而左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之左, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的之右。 例如:查询员工的编号,姓名,工资,部门名 select emp.empno,emp.ename,emp.sal,dept.dname from emp,dept where (emp.deptno = dept.deptno) and (emp.sal > 1500) (03)SELECT子句中避免使用*号 数据库在解析的过程中,会将*依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间 select empno,ename from emp; (04)用TRUNCATE替代DELETE (05)尽量多使用COMMIT 因为COMMIT会释放回滚点 (06)用WHERE子句替换HAVING子句 WHERE先执行,HAVING后执行 (07)多使用内部函数提高SQL效率 (08)使用表的别名 salgrade s (09)使用列的别名 ename e 总之,数据库优化不是一天的课题,你得在长期工作实践中,进行反复测试与总结,希望学员们日后好好领会
-------------------------------------JDBC就是发送sql语句的技术--------------------------------------------------------------
2.4 JDBC接口核心的API
java.sql.* 和 javax.sql.*
|- Driver接口: 表示java驱动程序接口。所有的具体的数据库厂商要来实现此接口。
|- connect(url, properties): 连接数据库的方法。
url: 连接数据库的URL
URL语法: jdbc协议:数据库子协议://主机:端口/数据库
user: 数据库的用户名
password: 数据库用户密码
|- DriverManager类: 驱动管理器类,用于管理所有注册的驱动程序
|-registerDriver(driver) : 注册驱动类对象
|-Connection getConnection(url,user,password); 获取连接对象
|- Connection接口: 表示java程序和数据库的连接对象。
|- Statement createStatement() : 创建Statement对象
|- PreparedStatement prepareStatement(String sql) 创建PreparedStatement对象
|- CallableStatement prepareCall(String sql) 创建CallableStatement对象
|- Statement接口: 用于执行静态的sql语句
|- int executeUpdate(String sql) : 执行静态的更新sql语句(DDL,DML)
|- ResultSet executeQuery(String sql) :执行的静态的查询sql语句(DQL)
|-PreparedStatement接口:用于执行预编译sql语句
|- int executeUpdate() : 执行预编译的更新sql语句(DDL,DML)
|-ResultSet executeQuery() : 执行预编译的查询sql语句(DQL)
|-CallableStatement接口:用于执行存储过程的sql语句(call xxx)
|-ResultSet executeQuery() : 调用存储过程的方法
|- ResultSet接口:用于封装查询出来的数据
|- boolean next() : 将光标移动到下一行
|-getXX() : 获取列的值
-------------------------------------------------------
1. 注意:静态方法不可以使用类中定义的泛型
因为类中的泛型需要在对象初始化时指定具体的类型,而静态优先于对象存在。那么类中的静态方法就需要单独进行泛型声明,声明泛型一定要写在static后,返回值类型之前
2. 反射麻烦--》内省麻烦-》BeanUtil
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性。
sun公司的内省API过于繁琐,所以Apache组织结合很多实际开发中的应用场景开发了一套简单、易用的API操作Bean的属性——BeanUtils。
3. 路径
a.在Eclipse中,当前路径是工程的根目录
b classpath路径
1.1.1. classpath路径说明
在Java程序中,一般情况下使用绝对路径还是相对路径都不太合适,因为Java程序的jar包所放的位置不确定,执行java程序时当前的路径也不确定,所以不合适。一般在Java程序中我们会把资源放到classpath中,然后使用classpath路径查找资源。
Classpath路径:就是使用classpath目前的路径。
1.1.2. 获取classpath中的资源(InputStream)
public static void main(String[] args) throws Exception { Class clazz = new ClassPathTest().getClass(); // 开头的'/'表示classpath的根目录,这个是表示从classpath的根目录中开始查找资源 InputStream in = clazz.getResourceAsStream("/cn/itcast/my.properties"); // 如果开头没有'/',表示从当前这个class所在的包中开始查找 InputStream in2 = clazz.getResourceAsStream("my.properties"); }
---------------------------JavaScript---------------------------------
PS:isNaN()判断是否是一个数字
3. XML
4.2 XML解析方式(原理不同)
DOM解析
Domj4读取xml文件 节点: Iterator Element.nodeIterator(); //获取当前标签节点下的所有子节点(不包含孙节点) 标签: Element Document.getRootElement(); //获取xml文档的根标签 Element ELement.element("标签名") //指定名称的第一个子标签 Iterator<Element> Element.elementIterator("标签名");// 指定名称的所有子标签 List<Element> Element.elements(); //获取所有子标签 属性: String Element.attributeValue("属性名") //获取指定名称的属性值 Attribute Element.attribute("属性名");//获取指定名称的属性对象 Attribute.getName() //获取属性名称 Attibute.getValue() //获取属性值 List<Attribute> Element.attributes(); //获取所有属性对象 Iterator<Attribute> Element.attibuteIterator(); //获取所有属性对象 文本: Element.getText(); //获取当前标签的文本 Element.elementText("标签名") //获取当前标签的指定名称的子标签的文本内容
2 Dom4j修改xml文档 2.1 写出内容到xml文档 XMLWriter writer = new XMLWriter(OutputStream, OutputForamt) wirter.write(Document); 2.2 修改xml文档的API 增加: DocumentHelper.createDocument() 增加文档 addElement("名称") 增加标签 addAttribute("名称",“值”) 增加属性 修改: Attribute.setValue("值") 修改属性值 Element.addAtribute("同名的属性名","值") 修改同名的属性值 Element.setText("内容") 修改文本内容 删除 Element.detach(); 删除标签 Attribute.detach(); 删除属性
SAX解析
总结: 1)Dom4j修改xml文档 new XMLWrier(); ...... 2)xPath技术: 快速查询xml节点 selectNodes() selectSinglNode(); xpath表达式语言 3) SAX解析 SAXParser parse parser() DefaultHandler类: startElement(); characters(); endElement();
4.3 XML解析工具
DOM解析原理:
1)JAXP (oracle-Sun公司官方)
2)JDOM工具(非官方)
3)Dom4J工具(非官方)
三大框架(默认读取xml的工具就是Dom4j)
.......
SAX解析原理:
1)Sax解析工具(oracle-sun公司官方)
===================================
DOM解析原理:一次性把xml文档加载进内存,然后在内存中构建Document树。 对内存要求比较要。
缺点: 不适合读取大容量的xml文件,容易导致内存溢出。
SAX解析原理: 加载一点,读取一点,处理一点。对内存要求比较低。
============DOM解析 vs SAX解析 ========
DOM解析 |
SAX解析 |
原理: 一次性加载xml文档,不适合大容量的文件读取 |
原理: 加载一点,读取一点,处理一点。适合大容量文件的读取 |
DOM解析可以任意进行增删改成 |
SAX解析只能读取 |
DOM解析任意读取任何位置的数据,甚至往回读 |
SAX解析只能从上往下,按顺序读取,不能往回读 |
DOM解析面向对象的编程方法(Node,Element,Attribute),Java开发者编码比较简单。 |
SAX解析基于事件的编程方法。java开发编码相对复杂。 |
=============
5.常见的市面上web服务软件
javase的规范,包含IO流,线程,集合,socket编程。。。。
WebLogic: BEA公司的产品。 收费的。支持JavaEE规范。
WebSphere: IBM公司的产品。收费的。支持JavaEE规范
JBoss: Redhat公司的产品。收费的。支持JavaEE规范
Tomcat: 开源组织Apache的产品。免费的。支持部分的JavaEE规范。(servlet、jsp。jdbc,但 ejb, rmi不支持)
==============
Web应用的目录结构
|- WebRoot : web应用的根目录
|- 静态资源(html+css+js+image+vedio)
|- WEB-INF
: 固定写法。
|-classes: (可选)固定写法。存放class字节码文件
|-lib: (可选)固定写法。存放jar包文件。
|-web.xml
注意:
1)WEB-INF目录里面的资源不能通过浏览器直接访问
2)如果希望访问到WEB-INF里面的资源,就必须把资源配置到一个叫web.xml的文件中。
====================================
6.HTTP
HttpServletResponse她也是一个对象,封装响应的信息。
PS:也就是请求和响应是在一起执行的
HTTP请求
1)GET方式提交
a)地址栏(URI)会跟上参数数据。以?开头,多个参数之间以&分割。
GET /day09/testMethod.html?name=eric&password=123456 HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/day09/testMethod.html Connection: keep-alive |
b)GET提交参数数据有限制,不超过1KB。
c)GET方式不适合提交敏感密码。
d)注意: 浏览器直接访问的请求,默认提交方式是GET方式
2)POST方式提交
a)参数不会跟着URI后面。参数而是跟在请求的实体内容中。没有?开头,多个参数之间以&分割。
POST /day09/testMethod.html HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/day09/testMethod.html Connection: keep-alive
name=eric&password=123456 |
b)POST提交的参数数据没有限制。
c)POST方式提交敏感数据。
===============================================================================
7.servlet 初始化 : 构造函数-》init-》service-》destory
Servlet的自动加载
默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。
改变servlet创建对象的时机: 提前到加载web应用的时候!!!
在servlet的配置信息中,加上一个<load-on-startup>即可!!
<servlet> <servlet-name>LifeDemo</servlet-name> <servlet-class>gz.itcast.c_life.LifeDemo</servlet-class> <!-- 让servlet对象自动加载 --> <load-on-startup>1</load-on-startup> 注意: 整数值越大,创建优先级越低!! </servlet> |
ServletConfig对象
9.1 作用
ServletConfig对象: 主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)
ServletContext对象
10.1 引入
ServletContext对象 ,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一 个ServletContext对象。
10.2 对象创建和得到
创建时机:加载web应用时创建ServletContext对象。
得到对象: 从ServletConfig对象的getServletContext方法得到
====================================================================
软件中的会话
一次会话: 打开浏览器 -> 访问一些服务器内容 -> 关闭浏览器
3.4 Cookie的细节 1)void setPath(java.lang.String uri) :
设置cookie的有效访问路径。有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。 2)void setMaxAge(int expiry) : 设置cookie的有效时间。 正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。 负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!! 零:表示删除同名的cookie数据 3)Cookie数据类型只能保存非中文字符串类型的。可以保存多个cookie,但是浏览器一般只允许存放300个Cookie,
每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
Cookie的局限:
1)Cookie只能存字符串类型。不能保存对象
2)只能存非中文。
3)1个Cookie的容量不超过4KB。
如果要保存非字符串,超过4kb内容,只能使用session技术!!!
总结: 1)会话管理: 浏览器和服务器会话过程中的产生的会话数据的管理。 2)Cookie技术: new Cookie("name","value") response.addCookie(coookie) request.getCookies() 3)Session技术 request.getSession(); setAttrbute("name","会话数据"); getAttribute("会话数据")
===================Web加载资源
4.4 Sesson细节 1)java.lang.String getId() : 得到session编号 2)两个getSession方法: getSession(true) / getSession() : 创建或得到session对象。没有匹配的session编号,自动创建新的session对象。 getSession(false): 得到session对象。没有匹配的session编号,返回null 3)void setMaxInactiveInterval(int interval) : 设置session的有效时间 session对象销毁时间: 3.1 默认情况30分服务器自动回收 3.2 修改session回收时间 3.3 全局修改session有效时间
8.JSP
Jsp的执行过程
问题: 访问http://localhost:8080/day12/01.hello.jsp 如何显示效果?
1)访问到01.hello.jsp页面,tomcat扫描到jsp文件,在%tomcat%/work把jsp文件翻译成java源文件
(01.hello.jsp -> _01_hello_jsp.java) (翻译)
2)tomcat服务器把java源文件编译成class字节码文件 (编译)
(_01_hello_jsp.java -> _01_hello_jsp.class)
3)tomcat服务器构造_01_hello_jsp类对象
4)tomcat服务器调用_01_hello_jsp类里面方法,返回内容显示到浏览器。
第一次访问jsp:
走(1)(2)(3)(4)
第n次访问jsp:
走(4)
注意:
1)jsp文件修改了或jsp的临时文件被删除了,要重新走翻译(1)和编译(2)的过程
===================================
为什么Jsp就是servlet!!! 因为Jsp继承字HttpServlet
jsp翻译的java文件:
public final class _01_hello_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
HttpJspBase类:
public abstract class org.apache.jasper.runtime.HttpJspBase extends javax.servlet.http.HttpServlet implements javax.servlet.jsp.HttpJspPage {
结论: Jsp就是一个servlet程序!!!
servlet的技术可以用在jsp程序中
jsp的技术并不是全部适用于servlet程序!
Servlet的生命周期:
1)构造方法(第1次访问)
2)init方法(第1次访问)
3)service方法
4)destroy方法
Jsp的生命周期
1)翻译: jsp->java文件
2)编译: java文件->class文件(servlet程序)
3)构造方法(第1次访问)
4)init方法(第1次访问):_jspInit()
5)service方法:_jspService()
6)destroy方法:_jspDestroy()
=================Struts======================
PS:struts其实也是servlet封装,提高开发效率!
也可以说,Struts2 = struts1 + xwork
Struts2执行流程
服务器启动:
1. 加载项目web.xml
2. 创建Struts核心过滤器对象, 执行filter à init()
struts-default.xml, 核心功能的初始化
struts-plugin.xml, struts相关插件
struts.xml 用户编写的配置文件
访问:
3. 用户访问Action, 服务器根据访问路径名称,找对应的aciton配置, 创建action对象
4. 执行默认拦截器栈中定义的18个拦截器
5. 执行action的业务处理方法
-----------------------------------------------------------------
拦截器(先睹为快):
拦截器功能与过滤器功能类似。
区别:
共同点: 都拦截资源!
区别:
过滤器,拦截器所有资源都可以; (/index.jsp/servlet/img/css/js)
拦截器,只拦截action请求。
拦截器是struts的概念,只能在struts中用。
过滤器是servlet的概念,可以在struts项目、servlet项目用。
// 面试题: 拦截器什么时候执行? (访问/启动) 先执行action类创建,先执行拦截器?
// --》 1. 用户访问时候按顺序执行18个拦截器;
//---》 2. 先执行Action类的创建,再执行拦截器; 最后拦截器执行完,再执行业务方法
=============================================================
PS:如果没有.action,不做处理。
================值栈==================
=====================拦截器===================
拦截器
1.1 概述
ü 基本概念
Intercetor, 即为拦截器。
1) 在Struts2中,把每一个功能都用一个个的拦截器实现;用户想用struts的哪个功能的时候,可以自由组装使用。
2)Struts2中,为了方法用户对拦截器的引用,提供了拦截器栈的定义,里面可以包含多个拦截器。 文件夹(文件, 文件2) 拦截器栈(拦截器,拦截器2)
3)Struts2中,如果用户没有指定执行哪些拦截器,struts2有一个默认执行的栈,defaultStack;
一旦如果用户有指定执行哪些拦截器,默认的拦截器栈就不会被执行
拦截器的设计,就是基于组件设计的应用!
===================Hibernate===================================
Hibernate Api
|-- Configuration 配置管理类对象
config.configure(); 加载主配置文件的方法(hibernate.cfg.xml)
默认加载src/hibernate.cfg.xml
config.configure(“cn/config/hibernate.cfg.xml”); 加载指定路径下指定名称的主配置文件
config.buildSessionFactory(); 创建session的工厂对象
|-- SessionFactory session的工厂(或者说代表了这个hibernate.cfg.xml配置文件)
sf.openSession(); 创建一个sesison对象
sf.getCurrentSession(); 创建session或取出session对象
|--Session session对象维护了一个连接(Connection), 代表了与数据库连接的会话。
Hibernate最重要的对象: 只用使用hibernate与数据库操作,都用到这个对象
session.beginTransaction(); 开启一个事务; hibernate要求所有的与数据库的操作必须有事务的环境,否则报错!
=========================对象的状态==========================================
对象的状态
举例: User user = new User();
Hibernate中对象的状态: 临时/瞬时状态、持久化状态、游离状态。
ü 临时状态
特点:
直接new出来的对象;
不处于session的管理;
数据库中没有对象的记录;
ü 持久化状态
当调用session的save/saveOrUpdate/get/load/list等方法的时候,对象就是持久化状态。
处于持久化状态的对象,当对对象属性进行更改的时候,会反映到数据库中!
特点:
处于session的管理;
数据库中有对应的记录;
ü 游离状态
特点
不处于session的管理;
数据库中有对应的记录
Session关闭后,对象的状态;
=================一级缓存=======================================
二、一级缓存
为什么要用缓存?
目的:减少对数据库的访问次数!从而提升hibernate的执行效率!
Hibernate中缓存分类:
一级缓存
二级缓存
ü 概念
1)Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效!
2)当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session的缓存中。
3)Session的缓存由hibernate维护, 用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。
特点:
只在(当前)session范围有效,作用时间短,效果不是特别明显!
在短时间内多次操作数据库,效果比较明显!
ü 缓存相关几个方法的作用
session.flush(); 让一级缓存与数据库同步
session.evict(arg0); 清空一级缓存中指定的对象
session.clear(); 清空一级缓存中缓存的所有对象
在什么情况用上面方法?
批量操作使用使用:
Session.flush(); // 先与数据库同步
Session.clear(); // 再清空一级缓存内容
=================懒加载=================================
三、懒加载
ü 面试题3: get、load方法区别?
get: 及时加载,只要调用get方法立刻向数据库查询
load:默认使用懒加载,当用到数据的时候才向数据库查询。
ü 懒加载:(lazy)
概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。
目的:提供程序执行效率!
ü lazy 值
true 使用懒加载
false 关闭懒加载
extra (在集合数据懒加载时候提升效率)
在真正使用数据的时候才向数据库发送查询的sql;
如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!
ü 懒加载异常
n Session关闭后,不能使用懒加载数据!
n 如果session关闭后,使用懒加载数据报错:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
如何解决session关闭后不能使用懒加载数据的问题?
// 方式1: 先使用一下数据
//dept.getDeptName();
// 方式2:强迫代理对象初始化
Hibernate.initialize(dept);
// 方式3:关闭懒加载
设置lazy=false;
// 方式4: 在使用数据之后,再关闭session!
========================二级缓存==============================================
三、二级缓存
Hibernate提供的缓存
有一级缓存、二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!
一级缓存:
基于Session的缓存,缓存内容只在当前session有效,session关闭,缓存内容失效!
特点:
作用范围较小! 缓存的事件短。
缓存效果不明显。
概述
二级缓存:
Hibernate提供了基于应用程序级别的缓存, 可以跨多个session,即不同的session都可以访问缓存数据。 这个换存也叫二级缓存。
Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。
如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。
===============================Spring============================================
Spring框架
2.1 专业术语了解
PS:依赖注入和控制反转其实是一个概念
组件/框架设计
侵入式设计
引入了框架,对现有的类的结构有影响;即需要实现或继承某些特定类。
例如: Struts框架
非侵入式设计
引入了框架,对现有的类结构没有影响。
例如:Hibernate框架 / Spring框架
控制反转:
Inversion on Control , 控制反转 IOC
对象的创建交给外部容器完成,这个就做控制反转.
依赖注入, dependency injection
处理对象的依赖关系
区别:
控制反转, 解决对象创建的问题 【对象创建交给别人】
依赖注入,
在创建完对象后, 对象的关系的处理就是依赖注入 【通过set方法依赖注入】
AOP
面向切面编程。切面,简单来说来可以理解为一个类,由很多重复代码形成的类。
切面举例:事务、日志、权限;
============================================================
PS:使用注解解决依赖注入的问题。
===================================================
========================代理===============================
在Spring的AOP编程中,
如果加入容器的目标对象有实现接口,用JDK代理;
如果目标对象没有实现接口,用Cglib代理;
静态代理,
1) 代理对象,要实现与目标对象一样的接口;
动态代理,
1)代理对象,不需要实现接口;
2)代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型;);
3) 动态代理, JDK代理, 接口代理;
Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。
========================AOP====================================
Aop, aspect object programming 面向切面编程
功能: 让关注点代码与业务代码分离!
关注点,
重复代码就叫做关注点;
切面,
关注点形成的类,就叫切面(类)!
面向切面编程,就是指 对很多功能都有的重复的代码抽取,再在运行的时候网业务方法上动态植入“切面类代码”。
切入点,
执行目标对象方法,动态植入切面代码。
可以通过切入点表达式,指定拦截哪些类的哪些方法; 给指定的类在运行的时候植入切面类代码。
========================事务的控制================================
编程式事务控制
自己手动控制事务,就叫做编程式事务控制。
Jdbc代码:
Conn.setAutoCommite(false); // 设置手动控制事务
Hibernate代码:
Session.beginTransaction(); // 开启一个事务
【细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制】
(比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)
声明式事务控制
Spring提供了对事务的管理, 这个就叫声明式事务管理。
Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦。
Spring声明式事务管理,核心实现就是基于Aop。
【粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。】
(因为aop拦截的是方法。)
Spring声明式事务管理器类:
Jdbc技术:DataSourceTransactionManager
Hibernate技术:HibernateTransactionManager
=============================事物的属性==================================================
介绍事务的属性: http://blog.sina.com.cn/s/blog_4b5bc0110100z7jr.html
介绍事物:http://www.cnblogs.com/fjdingsd/p/5273008.html
=========================SpringMVC====================================
PS:DispatcherServlet是选择并决定将要发送给哪个控制器
PS:SpringMVC是spring的后续产品
============================================
springmvc与struts2的区别
1)springmvc的入口是一个servlet,即前端控制器,例如:*.action
struts2入口是一个filter过虑器,即前端过滤器,例如:/*
2)springmvc是基于方法开发,传递参数是通过方法形参,可以设计为单例
struts2是基于类开发,传递参数是通过类的属性,只能设计为多例
3)springmvc通过参数解析器是将request对象内容进行解析成方法形参,将响应数据和页面封装成
ModelAndView对象,最后又将模型数据通过request对象传输到页面
struts采用值栈存储请求和响应的数据,通过OGNL存取数据
====================MyBatis工作流程==========================
mybatis工作流程
1)通过Reader对象读取src目录下的mybatis.xml配置文件(该文本的位置和名字可任意)
2)通过SqlSessionFactoryBuilder对象创建SqlSessionFactory对象
3)从当前线程中获取SqlSession对象
4)事务开始,在mybatis中默认
5)通过SqlSession对象读取StudentMapper.xml映射文件中的操作编号,从而读取sql语句
6)事务提交,必写
7)关闭SqlSession对象,并且分开当前线程与SqlSession对象,让GC尽早回收
在Spring的AOP编程中,
如果加入容器的目标对象有实现接口,用JDK代理;
如果目标对象没有实现接口,用Cglib代理;
posted on 2017-09-20 17:23 biyangqiang 阅读(245) 评论(0) 编辑 收藏 举报