50.如何将一个字符串转换为arraylist?
string 转 ArrayList
先将字符串按照某个字符切割,转为string数组
然后用Arrays的asList方法,将数组转为List
public class test1 {
public static void main(String[] args) {
//string 转 ArrayList
String str1 = "a,b,c";
ArrayList<String> list =
new ArrayList<String>(Arrays.asList(str1.split(",")));
System.out.println(list);
}
}
ArrayList 转 string
public class test1 {
public static void main(String[] args) {
//ArrayList 转 string
ArrayList<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
System.out.println(list);//[a, b, c]
String list_str = StringUtils.join(list,",");
System.out.println(list_str);//a,b,c
}
}
51.HashMap的实现原理
HashMap的主干是一个Entry数组。
Entry是HashMap的基本组成单元,
每一个Entry包含一个key-value键值对。
HashMap基于hashing原理,
我们通过put()和get()方法储存和获取对象。
当我们将键值对传递给put()方法时,
它调用键对象的hashCode()方法
来计算hashcode,
让后找到bucket位置来储存值对象。
当获取对象时,
通过键对象的equals()方法
找到正确的键值对,
然后返回值对象。
HashMap使用链表来解决碰撞问题,
当发生碰撞了,
对象将会储存在链表的下一个节点中。
HashMap在每个链表节点中储存键值对对象。
当两个不同的键对象的hashcode
相同时会发生什么?
它们会储存在同一个bucket位置的链表中。
键对象的equals()方法用来找到键值对。
因为HashMap的好处非常多,
我曾经在电子商务的应用中使用HashMap作为缓存。
因为金融领域非常多的运用Java,
也出于性能的考虑,
我们会经常用到HashMap和ConcurrentHashMap。
HashMap由数组+链表组成的,
数组是HashMap的主体,
链表则是主要为了解决哈希冲突而存在的,
如果定位到的数组位置不含链表
当前entry的next指向null,
那么对于查找,
添加等操作很快,
仅需一次寻址即可;
如果定位到的数组包含链表,
对于添加操作,
其时间复杂度为O(n),
首先遍历链表,
存在即覆盖,
否则新增;
对于查找操作来讲,
仍需遍历链表,
然后通过key对象的equals方法逐一比对查找。
所以,性能考虑,HashMap中的链表出现越少,
性能才会越好。
52.List、Set、Map之间的区别
List、Set是实现了Collection接口的子接口;
而Map是另一个集合接口。
1元素重复性:
List允许有重复的元素。
任何数量的重复元素
都可以在不影响现有重复元素的值
及其索引的情况下插入到List集合中;
Set集合不允许元素重复。
Set以及所有实现了Set接口的类
都不允许重复值的插入,
若多次插入同一个元素时,
在该集合中只显示一个;
Map以键值对的形式对元素进行存储。
Map不允许有重复键,
但允许有不同键对应的重复的值;
2.元素的有序性:
List及其所有实现类保持了
每个元素的插入顺序;
Set中的元素都是无序的;
但是某些Set的实现类
以某种殊形式对其中的元素进行排序,
如:LinkedHashSet按照元素的
插入顺序进行排序;
Map跟Set一样对元素进行无序存储,
但其某些实现类对元素进行了排序。
如:TreeMap根据键对其中的元素进行升序排序;
3.元素是否为空值:
1.List允许任意数量的空值;
2.Set最多允许一个空值的出现;
当向Set集合中添加多个null值时,
在该Set集合中只会显示一个null元素
3.Map只允许出现一个空键,
但允许出现任意数量的空值;
---------------------------------
总结:
List中的元素:
有序、可重复、可为空;
Set中的元素:
无序、不重复、只有一个空元素;
Map中的元素:
无序、键不重,值可重、可一个空键、多可空值;
53.HashMap 的长度为什么是2的幂次方
1.减小哈希冲突概率
假如当前Entry数组长度为len,
插入节点时,
需要对key的hashcode进行二次哈希,
然后跟len-1相与
得到的值一定小于len,避免数组越界
如果len是2的N次方,
那么len-1的后N位二进制一定是全1
假设有两个key,
他们的hashcode不同,
分别为code1和code2
code1和code2分别与一个后N位全1的二进制相与,
结果一定也不同
但是,如果code1和code2分别
与一个后N位非全1的二进制相与,
结果有可能相同
也就是说,
如果len是2^N,
不同hashcode的key
计算出来的数组下标一定不同;
否则,
不同hashcode的key
计算出来的数组下标一定相同。
所以HashMap长度为全1,
可以减小哈希冲突概率。
----------------------
2.提高计算下标的效率
如果len的二进制后n位非全1,
与len-1相与时,
0与1相与需要取反。
如果len的二进制后n位全1,
完全不需要取反。
如果len为2^N,
那么与len-1相与,
跟取余len等价,
而与运算效率高于取余。
如果len不是2^N,
与len-1相与,
跟取余len不等价。
54.集合框架中的泛型有什么优点?
首先,
了解一下Java关于泛型的概念。
泛型,在C++中被称为模板,
就是一种抽象的编程方式。
当我们定义类和方法的时候,
可以用一种通用的方式进行定义,
而不必写出具体的类,
这些未知的东西会在真正使用的时候在确定。
对于集合类来说,
它们可以存放各种类型的元素。
如果在存放之前,
就能确定元素的类型,
那么就可以更加直观,
也让代码更加简洁。
说明:
java的泛型是停留在编译层的,
也就是说JVM在对待泛型数据的时候,
依然会把它们看成是Object类型,
只不过在使用这些元素的时候,
JVM会自动帮助我们进行相应的类型转换。
总结:
集合使用泛型之后,
可以达到元素类型明确的目的,
避免了手动类型转换的过程,
同时,也让我们更加明确
容器保存的是什么类型的数据。
55.我们能否使用任何类作为Map的key?
1、可以
但是做为key的数据有如下要求:
2、首先,
要求明确一点Map集合存储数据的
主要目的是为了查找
而List集合是为了输出
3、既然是查找那么就要涉及到对象比较
我们说了如果要进行对象比较
就必须覆写Object类中的equals()、hasCode()
至少覆写equals()方法 简单理解:
自己定义的类如果要想实现对象比较
就必须至少覆写equals()方法
4、或则这么说只要是自己定义的类
要想将其作为key
就必须覆写equals()方法
5、实际工作中 key的类型一定是String型
(95%通用) 其余的5%是没事找事的
6、按标准开发、你会感到事半功倍,
不要没事给自己找事,
当然求知精神是值得肯定的。
56.Map接口提供了哪些不同的集合视图?
Map接口提供了三个集合视图:
1.Set keyset():
返回map中包含的所有key的一个Set视图。
集合是受map支持的,
map的变化会在集合中反映出来,
反之亦然。
当一个迭代器正在遍历一个集合时,
若map被修改了(除迭代器自身的移除操作以外),
迭代器的结果会变为未定义。
集合支持通过
Iterator的Remove、
Set.remove、
removeAll、
retainAll和clear操作进行元素移除,
从map中移除对应的映射。
它不支持add和addAll操作。
2.Collection values():
返回一个map中包含的
所有value的一个Collection视图。
这个collection受map支持的,
map的变化会在collection中反映出来,
反之亦然。
当一个迭代器正在遍历一个collection时,
若map被修改了(除迭代器自身的移除操作以外),
迭代器的结果会变为未定义。
集合支持通过
Iterator的Remove、
Set.remove、
removeAll、
retainAll和clear操作进行元素移除,
从map中移除对应的映射。
它不支持add和addAll操作。
3.Set> entrySet():
返回一个map钟包含的
所有映射的一个集合视图。
这个集合受map支持的,
map的变化会在collection中反映出来,
反之亦然。
当一个迭代器正在遍历一个集合时,
若map被修改了
除迭代器自身的移除操作,
以及对迭代器返回的entry进行setValue外,
迭代器的结果会变为未定义。
集合支持通过
Iterator的Remove、
Set.remove、
removeAll、
retainAll和clear操作进行元素移除,
从map中移除对应的映射。
它不支持add和addAll操作。
57.哪些集合类是线程安全的?
在集合框架中,有些类是线程安全的,
这些都是jdk1.1中的出现的。
在jdk1.2之后,
就出现许许多多非线程安全的类。
下面是这些线程安全的同步的类:
vector:
就比arraylist多了个同步化机制(线程安全),
因为效率较低,
现在已经不太建议使用。
在web应用中,
特别是前台页面,
往往效率(页面响应速度)是优先考虑的。
statck:堆栈类,先进后出
hashtable:就比hashmap多了个线程安全
enumeration:枚举,相当于迭代器
除了这些之外,
其他的都是非线程安全的类和接口。
线程安全的类其方法是同步的,
每次只能一个访问。
是重量级对象,
效率较低。
58.队列和栈是什么,列出它们的区别?
队列(Queue):
是限定只能在表的一端进行
插入和在另一端进行删除操作的线性表;
栈(Stack):
是限定只能在表的一端
进行插入和删除操作的线性表。
区别如下:
一、规则不同
1. 队列:先进先出(First In First Out)FIFO
2. 栈:先进后出(First In Last Out )FILO
二、对插入和删除操作的限定不同
1. 队列:只能在表的一端进行插入,
并在表的另一端进行删除;
2. 栈:只能在表的一端插入和删除。
三、遍历数据速度不同
1. 队列:基于地址指针进行遍历,
而且可以从头部或者尾部进行遍历,
但不能同时遍历,
无需开辟空间,
因为在遍历的过程中不影响数据结构,
所以遍历速度要快;
2. 栈:只能从顶部取数据,
也就是说最先进入栈底的,
需要遍历整个栈才能取出来,
而且在遍历数据的同时需要
为数据开辟临时空间,
保持数据在遍历前的一致性。
59.哪一个List实现了最快插入?
LinkedList和ArrayList
是另个不同变量列表的实现。
ArrayList的优势在于动态的增长数组,
非常适合初始时总长度未知的情况下使用。
LinkedList的优势在于在中间位置插入和删除操作,
速度是最快的。
LinkedList实现了List接口,
允许null元素。
此外LinkedList提供额外的
get,remove,insert方法
在LinkedList的首部或尾部。
这些操作使LinkedList可被
用作堆栈(stack),
队列(queue)
或双向队列(deque)。
ArrayList实现了可变大小的数组。
它允许所有元素,
包括null。
每个ArrayList实例都有一个容量(Capacity),
即用于存储元素的数组的大小。
这个容量可随着不断添加新元素而自动增加,
但是增长算法并没有定义。
当需要插入大量元素时,
在插入前可以调用ensureCapacity方法来
增加ArrayList的容量以提高插入效率。
60.什么时候使用ConcurrentHashMap?
快速失败的Java迭代器
可能会引发ConcurrentModifcationException
在底层集合迭代过程中被修改。
故障安全作为发生在实例中的一个副本
迭代是不会抛出任何异常的。
快速失败的故障安全范例定义了
当遭遇故障时系统是如何反应的。
例如,用于失败的快速迭代器ArrayList
和用于故障安全的迭代器ConcurrentHashMap。
ConcurrentHashMap被作为
故障安全迭代器的一个实例,
它允许完整的并发检索和更新。
当有大量的并发更新时,
ConcurrentHashMap此时可以被使用。
这非常类似于Hashtable,
但ConcurrentHashMap不锁定
整个表来提供并发,
所以从这点上ConcurrentHashMap的性能
似乎更好一些。
所以当有大量更新时
ConcurrentHashMap应该被使用。
61.什么是并发修改异常?
什么是并发修改异常:
当我们在遍历实现了collection接口
与iterator接口的集合时(List、Set、Map),
我们可以通过遍历索引
也可以通过迭代器进行遍历。
在我们使用迭代器进行遍历集合的时候,
会获取到当前集合的迭代对象。
在里面有封装了迭代器的remove方法
与集合自带的remove方法,
如果我们调用迭代器对象的remove方法
是没问题的,
但是当我们调用集合自带的remove方法时,
就会产生ConcurrentModificationException
并发修改异常。
也就是说,
当我们通过迭代器进行遍历集合的时候,
是不允许集合本身在结构上发生变化的。
62.什么是CopyOnWriteArrayList,它与ArrayList有何不同?
CopyOnWriteArrayList:
CopyOnWriteArrayList这是一个
ArrayList的线程安全的变体,
其原理大概可以通俗的理解为:
初始化的时候只有一个容器,
很常一段时间,
这个容器数据、
数量等没有发生变化的时候,
大家(多个线程),都是读取
假设这段时间里只发生读取的操作
同一个容器中的数据,
所以这样大家读到的数据都是
唯一、一致、安全的,
但是后来有人往里面增加了一个数据,
这个时候CopyOnWriteArrayList 底层实现
添加的原理是先copy出一个容器
可以简称副本,
再往新的容器里添加这个新的数据,
最后把新的容器的引用地址
赋值给了之前那个旧的的容器地址,
但是在添加这个数据的期间,
其他线程如果要去读取数据,
仍然是读取到旧的容器里的数据。
Vector
ArrayList
CopyOnWriteArrayList
这三个集合类都继承List接口
1、ArrayList是线程不安全的;
2、Vector是比较古老的线程安全的,
但性能不行;
3、CopyOnWriteArrayList在兼顾了
线程安全的同时,
又提高了并发性,
性能比Vector有不少提高
63.迭代器和枚举之间的区别?
在Java集合中,
我们通常都通过 “Iterator(迭代器)”
或 “Enumeration(枚举类)” 去遍历集合。
Enumeration是一个接口,它的源码如下:
package java.util;
public interface Enumeration<E> {
boolean hasMoreElements()
E nextElement();
}
Iterator也是一个接口,它的源码如下:
package java.util;
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
区别:
1 函数接口不同
Enumeration只有2个函数接口。
通过Enumeration,
我们只能读取集合的数据,
而不能对数据进行修改。
Iterator只有3个函数接口。
Iterator除了能读取集合的数据之外,
也能数据进行删除操作。
2.Iterator支持fail-fast机制,而Enumeration不支持。
Enumeration 是JDK 1.0添加的接口。
使用到它的函数包括Vector、Hashtable等类,
这些类都是JDK 1.0中加入的,
Enumeration存在的目的
就是为它们提供遍历接口。
Enumeration本身并没有支持同步,
而在Vector、Hashtable实现Enumeration时,
添加了同步。
而Iterator 是JDK 1.2才添加的接口,
它也是为了HashMap、ArrayList等集合
提供遍历接口。
Iterator是支持fail-fast机制的:
当多个线程对同一个集合的内容进行操作时,
就可能会产生fail-fast事件。
Java API规范建议,
对于较新的程序,
Iterator应优先于Enumeration,
因为“ Iterator在Java集合框架中
代替Enumeration。”
64.Hashmap如何同步?
1、使用 synchronized 关键字,
这也是最原始的方法。
synchronized(anObject)
{
value = map.get(key);
}
2、使用 JDK1.5 提供的锁
Java.util.concurrent.locks.Lock
lock.lock();
value = map.get(key);
lock.unlock();
3.可以使用 JDK1.5 提供的读写锁
java.util.concurrent.locks.ReadWriteLock
rwlock.readLock().lock();
value = map.get(key);
rwlock.readLock().unlock();
4.使用 JDK1.5 提供的
java.util.concurrent.ConcurrentHashMap 类
该类将 Map 的存储空间分为若干块,
每块拥有自己的锁,
大大减少了多个线程
争夺同一个锁的情况
value = map.get(key);
1、不同步确实最快,与预期一致。
2、四种同步方式中,
ConcurrentHashMap 是最快的,
接近不同步的情况。
3、synchronized 关键字非常慢
4、使用读写锁的读锁,比普通所稍慢。
1、如果 ConcurrentHashMap 够用,
则使用 ConcurrentHashMap。
2、如果需自己实现同步,
则使用 JDK1.5 提供的锁机制,
避免使用 synchronized 关键字。
65.IdentityHashMap和HashMap的区别?
前者比较key时是
“引用相等”
而后者是
“对象相等”,
即对于
k1和k2,当k1==k2时,
IdentityHashMap认为两个key相等,
而HashMap只有在k1.equals(k2) == true 时
才会认为两个key相等。
2.IdentityHashMap 允许使用null作为key和value.
不保证任何Key-value对的之间的顺序,
更不能保证他们的顺序
随时间的推移不会发生变化。
3.IdentityHashMap有其特殊用途,
比如序列化或者深度复制。或
者记录对象代理。
举个例子,
jvm中的所有对象都是独一无二的,
哪怕两个对象是同一个class的对象
而且两个对象的数据完全相同,
对于jvm来说,
他们也是完全不同的,
如果要用一个map来记录这样jvm中的对象,
你就需要用IdentityHashMap,
而不能使用其他Map实现
66.如何获取某个日期是当月的最后一天?
import java.util.Calendar;
public class Test {
public static void main(String[] args) {
System.out.println(daysCount(2010, 2));
}
public static int daysCount(int year, int month) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DATE, 0);
return cal.get(Calendar.DATE);
}
}
67.java中会存在内存泄漏吗,请简单描述
所谓内存泄露就是指
一个不再被程序使用的对象或变量
一直被占据在内存中。
Java中有垃圾回收机制,
它可以保证一对象不再被引用的时候,
即对象编程了孤儿的时候,
对象将自动被垃圾回收器
从内存中清除掉。
由于Java 使用有向图的方式
进行垃圾回收管理,
可以消除引用循环的问题,
例如有两个对象,相互引用,
只要它们和根进程不可达的,
那么GC也是可以回收它们的。
java中的内存泄露的情况:
长生命周期的对象持有
短生命周期对象的引用
就很可能发生内存泄露,
尽管短生命周期对象已经不再需要,
但是因为长生命周期对象
持有它的引用而导致不能被回收,
这就是java中内存泄露的发生场景,
通俗地说,
就是程序员可能创建了一个对象,
以后一直不再使用这个对象,
这个对象却一直被引用,
即这个对象无用
但是却无法被垃圾回收器回收的,
这就是java中可能出现
内存泄露的情况,
例如,缓存系统,
我们加载了一个对象放在缓存中(例如放在一个全局map对象中),
然后一直不再使用它,
这个对象一直被缓存引用,
但却不再被使用。
检查java中的内存泄露,
一定要让程序将各种分支情况
都完整执行到程序结束,
然后看某个对象是否被使用过,
如果没有,
则才能判定这个对象属于内存泄露。
如果一个外部类的实例对象的方法
返回了一个内部类的实例对象,
这个内部类对象被长期引用了,
即使那个外部类实例对象不再被使用,
但由于内部类持久外部类的实例对象,
这个外部类对象将不会被垃圾回收,
这也会造成内存泄露。
内存泄露的另外一种情况:
当一个对象被存储进HashSet集合中以后,
就不能修改这个对象中的
那些参与计算哈希值的字段了,
否则,对象修改后的哈希值
与最初存储进HashSet集合中时的哈希值
就不同了,
在这种情况下,
即使在contains方法使用该对象的
当前引用作为的参数去HashSet集合中
检索对象,
也将返回找不到对象的结果,
这也会导致无法从HashSet集合中
单独删除当前对象,
造成内存泄露
68.java中实现多态的机制是什么?
靠的是父类或接口的
引用指向子类或实现类的对象,
调用的方法是内存中
正在运行的那个对象的方法。
Java实现多态有三个必要条件:
继承、
重写、
向上转型。
继承:
在多态中必须存在
有继承关系的子类和父类。
重写:
子类对父类中某些方法进行重新定义,
在调用这些方法时
就会调用子类的方法。
向上转型:
在多态中需要将子类的引用
赋给父类对象,
只有这样该引用才能够具备
技能调用父类的方法和子类的方法。
只有满足了上述三个条件,
我们才能够在同一个继承结构中
使用统一的逻辑实现代码处理不同的对象,
从而达到执行不同的行为。
多态机制遵循的原则概括为
当超类对象引用变量引用子类对象时,
被引用对象的类型
而不是引用变量的类型
决定了调用谁的成员方法,
但是这个被调用的方法
必须是在超类中定义过的,
也就是说被子类覆盖的方法,
但是它仍然要根据继承链中
方法调用的优先级来确认方法,
该优先级为:
this.method(O)、
super.method(O)、
this.method((super)O)、
super.method((super)O)。
69.局部变量和成员变量的区别?
成员变量与局部变量的区别
1、在类中的位置不同
成员变量:
在类中方法外面
局部变量:
在方法或者代码块中,
或者方法的声明上
2、在内存中的位置不同,
成员变量:在堆中(方法区中的静态区)
局部变量:在栈中
3、生命周期不同
成员变量:
随着对象的创建而存在,
随着对象的消失而消失
局部变量:
随着方法的调用或者代码块的执行
而存在,
随着方法的调用完毕或者
代码块的执行完毕而消失
4、初始值
成员变量:
有默认初始值
局部变量:
没有默认初始值,
使用之前需要赋值,
否则编译器会报错
70.什么是匿名类,有什么好处?
简单地说:
匿名内部类就是没有名字的内部类。
什么情况下需要使用匿名内部类?
如果满足下面的一些条件,
使用匿名内部类是比较合适的:
只用到类的一个实例。
类在定义后马上用到。
类非常小(SUN推荐是在4行代码以下)
给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
匿名内部类不能有构造方法。
匿名内部类不能定义任何静态成员、方法和类。
匿名内部类不能是
public,protected,private,static。
只能创建匿名内部类的一个实例。
一个匿名内部类一定是在new的后面,
用其隐含实现一个接口或实现一个类。
因匿名内部类为局部内部类,
所以局部内部类的所有限制都对其生效。
71.jsp有哪些内置对象?作用分别是什么?
Page,
pageContext,
request,
response,
session,
application,
out,
config,
exception
Page指的是JSP被翻译成Servlet的对象的引用.
pageContext对象可以用来获得其他8个内置对象,
还可以作为JSP的域范围对象使用.
pageContext中存的值是当前的页面的作用范围
request代表的是请求对象,
可以用于获得客户机的信息,
也可以作为域对象来使用,
使用request保存的数据
在一次请求范围内有效。
Session代表的是一次会话,
可以用于保存用户的私有的信息,
也可以作为域对象使用,
使用session保存的数据在一次会话范围有效
Application:代表整个应用范围,
使用这个对象保存的数据
在整个web应用中都有效。
Response是响应对象,
代表的是从服务器向浏览器响应数据.
Out:JSPWriter是用于
向页面输出内容的对象
Config:指的是ServletConfig
用于JSP翻译成Servlet后
获得Servlet的配置的对象.
Exception:在页面中设置isErrorPage=”true”,
即可使用,
是Throwable的引用.用来获得页面的错误信息。
72.jsp有哪些动作?作用分别是什么?
jsp:include:
在页面被请求的时候引入一个文件。
jsp:useBean:
寻找或者实例化一个JavaBean。
jsp:setProperty:
设置JavaBean的属性。
jsp:getProperty:
输出某个JavaBean的属性。
jsp:plugin:
根据浏览器类型为Java插件生成OBJECT或EMBED标记。
jsp:forward:
把请求转到一个新的页面。
73.JSP中动态INCLUDE与静态INCLUDE的区别?
1. 静态include的结果是
把其他jsp引入当前jsp,
两者合为一体
动态include的结构是两者独立,
直到输出时才合并
看看jsp生成的java文件就可以知道了
2.正是因为这样,
动态include的jsp文件独立性很强,
是一个单独的jsp文件,
需要使用的对象,
页面设置,都必须有自己创建,
当然,还好它和include
它的页面的request范围是一致的.
而静态include纯粹是把代码
写在外面的一种共享方法,
所有的变量都是可以
和include它的主文件共享
,两者高度紧密结合,
不能有变量同名的冲突.
而页面设置也可以借用主文件的.
74.说一说Servlet的生命周期?
servlet 的生命周期是有四个阶段:
实例化 –>
初始化 –>
请求处理 –>
销毁
创建 Servlet 实例。
Web 容器调用 Servlet 的 init() 方法,
对Servlet 进行初始化。
Servlet 初始化后,
将一直存在于容器中,
用于响应客户端请求。
根据客户端的请求方式通过 Servlet 中service() 方法
去相应的 goGet(),或 doPost() 方法;
Web 容器销毁Servlet 时,
调用 Servlet 的 destroy() 方法,
通常在关闭Web容器之时销毁Servlet。
servlet 生命周期的三个方法:
init()方法:
Servlet实例化时调用此方法
Service()方法:
客户请求和响应调用此方法。
Destroy()方法:
释放内存,关闭web服务器调用此方法
75.说说JSP 的生命周期?
浏览器首先要请求一个以.jsp扩展名结尾的页面,
发起JSP请求,
然后,Web服务器读取这个请求,
使用JSP编译器把JSP页面
转化成一个Servlet类。
需要注意的是,
只有当第一次请求页面
或者是JSP文件发生改变的时候
JSP文件才会被编译,
然后服务器调用servlet类,
处理浏览器的请求。
一旦请求执行结束,
servlet会把响应发送给客户端。
jsp 的生命周期分为四个阶段:
编译
初始化
执行
销毁
76、XML技术的作用?
XML技术用于数据存储、
信息配置、
数据交换三方面。
可以将数据存储在XML中,
通过节点、
元素内容、
属性标示数据内容及关系。
可以使用XML很方便的做信息配置,
软件的各种配置参数和对象关系
都存贮在XML文件中。
在做数据交换平台时,
将数据组装成XML文件,
然后将XML文件压缩打包加密后
通过网络传送给接收者,
接收解密与解压缩后再同XML文件中
还原相关信息进行处理。
77.XML文档约束有哪几种?有什么区别?
有两种定义形式,
dtd文档类型定义和SchemaXML模式;
XML Schema 和DTD都用于文档验证,
但二者还有一定的区别,
本质区别是:Scheme本身是xml的,
可以被XML解析器解析,
这也是从DTD上发展Schema的根本目的。
另外,
XML Schema 是内容开放模型,
可扩展,功能性强,
而DTD可扩展性差。
XML Schema 支持丰富的数据类型,
而 DTD不支持元素的数据类型,
对属性的类型定义也很有限。
XML Schema 支持命名空间机制,
而DTD不支持。
XML Schema 可针对不同情况
对整个XML 文档或文档局部进行验证;
而 DTD缺乏这种灵活性。
XML Schema 完全遵循XML规范,
符合XML语法,
可以和DOM结合使用,
功能强大;
而DTD 语法本身有自身的语法和要求,
难以学习。
78.XML的解析方式有哪几种?有什么区别?
1.DOM解析:
DOM的全称是Document Object Model,
也即文档对象模型。
在应用程序中,
基于DOM的XML分析器
将一个XML文档转换成
一个对象模型的集合(通常称DOM树),
应用程序正是通过对
这个对象模型的操作,
来实现对XML文档数据的操作。
通过DOM接口,
应用程序可以在任何时候
访问XML文档中的任何一部分数据,
因此,这种利用DOM接口的机制
也被称作随机访问机制。
2.SAX解析:
SAX的全称是Simple APIs for XML,
也即XML简单应用程序接口。
与DOM不同,
SAX提供的访问模式是一种顺序模式,
这是一种快速读写XML数据的方式。
当使用SAX分析器对XML文档进行分析时,
会触发一系列事件,
并激活相应的事件处理函数,
应用程序通过这些事件处理函数
实现对XML文档的访问,
因而SAX接口也被称作事件驱动接口。
3.JDOM解析:
JDOM采用了Java中的Collection架构来封装集合,
是Java爱好者更加熟悉的模式
4.DOM4J解析:
xml解析器一次性把整个xml文档加载进内存,
然后在内存中构建一颗Document的对象树,
通过Document对象,
得到树上的节点对象,
通过节点对象访问(操作)到xml文档的内容
79.Http请求的Get和Post的区别?
1. get从地址栏以明文的方式提交请求
信息内容
?username=admin&password=123,
用户可见,
而post从请求正文提交请求信息内容,
用户不可见。
2. get提交因为是从地址栏传递,
而浏览器的地址栏长度有限制,
不能提交大数据
post从请求正文传递信息内容,
对文件大小无限制,
文件上传只能选择post
3. request对象是服务器获取请求信息
从请求头,请求正文中获取
我们可以使用request.setCharacterEncoding方法
修改请求对象字符编码信息,
但是不能修改地址栏字符编码。
get从地址栏传递信息,
不能使用request.setCharacterEncoding这个方法
去修改字符编码。
post从请求正文以form表单形式提交,
所以可以使用request.setCharacterEncoding
这个方法去修改字符编码。
4. 总结: 能够使用post提交尽量使用post提交。
80.ServletConfig对象和ServletContext对象有什么区别?
一个Servlet对应有一个ServletConfig对象,
可以用来读取初始化参数。
一个webapp对应一个ServletContext对象。
ServletContext对象
获取初始化定义的参数。
ServletContext对象可以通过
context.getResourceAsStream("/PATH");
或者context.getRealPath("/")。
去获取webapp的资源文件。
ServletContext对象的
setAttribute(String name,Object o)方法
可以将对象存储在Context作用范围域
又称为全局作用范围域,
在整个web应用当中可以共享.
ServletContext对象
可以和服务器进行通讯,
比如写信息到服务器的日志信息当中。。
81.Servlet的会话机制?
HTTP 是一种无状态协议,
这意味着每次客户端检索网页时,
都要单独打开一个服务器连接,
因此服务器不会记录下
先前客户端请求的任何信息。
它与FTP、Telnet等协议不同,
FTP等协议可以记住用户的连接信息。
会话(Session)是指一个终端用户
与交互系统进行通信的时间间隔,
通常指从登陆系统到注销系统之间
所经过的时间以及如果需要的话,
可能还有一定操作空间。
JSP有四种方式实现会话跟踪功能。
Cookie
服务器在响应请求时
可以将一些数据以"键-值"对的形式
通过响应信息保存在客户端。
当浏览器再次访问相同的应用时,
会将原先的存有session ID的Cookie
通过请求信息带到服务器端,
网络服务器通过识别唯一的session ID来
代表每个客户端,
从而识别这个客户端接下来的请求。
用于会话跟踪的Cookie叫做会话Cookie。
Servlet规范中会话跟踪的cookie名字
必须是JSESSIONID,
保存在浏览器的内存中。
Cookie可以用于保持用户的会话状态,
但Cookie信息保存在客户端,
存在较大的安全隐患,
且一般浏览器对Cookie的数目
及数据大小有严格的限制。
在Web应用中,
一般情况下通过HttpSession对象保持会话状态
Session
Session技术则是
服务端的解决方案,
它是通过服务器来保持状态的。
在Java中是通过调用
HttpServletRequest的getSession方法
使用true作为参数创建的。
在创建了Session的同时,
服务器会为该Session生成唯一的Session id,
而这个Session id在随后的请求中
会被用来重新获得已经创建的Session;
在Session被创建之后,
就可以调用Session相关的方法
往Session中增加内容了,
而这些内容只会保存在服务器中,
发到客户端的只有Session id;
当客户端再次发送请求的时候,
会将这个Session id带上,
服务器接受到请求之后
就会依据Session id找到相应的Session,
从而再次使用之。
正式这样一个过程,
用户的状态也就得以保持了。
隐藏表单域
隐藏表单域是将会话ID
添加到HTML的隐藏表单中
(类型为hidden的input)。
重定向和转发
重写URL
把会话ID编码在URL中。
counter.jsp;jsessionnid=be8d697876787876befdbde898789098980
对于URL复写,
服务器从请求的URI中提取出会话ID,
并把该请求与相应的会话关联起来,
然后在访问会话数据的时候,
JSP页面所进行的处理方式
就和使用cookie跟踪会话id时
所使用的方式完全相同。
所以sesssion的实现
要依靠cookie或URL复写技术。
82.Filter是什么?有什么作用?
过滤器是处于客户端与服务器
资源文件之间的一道过滤网,
在访问资源文件之前,
通过一系列的过滤器对请求进行修改、判断等,
把不符合规则的请求在中途拦截或修改。
也可以对响应进行过滤,
拦截或修改响应。
浏览器发出的请求先递交给第一个filter进行过滤,
符合规则则放行,
递交给filter链中的下一个过滤器进行过滤。
过滤器在链中的顺序
与它在web.xml中配置的顺序有关,
配置在前的则位于链的前端。
当请求通过了链中所有过滤器后
就可以访问资源文件了,
如果不能通过,
则可能在中间某个过滤器中被处理掉。
在doFilter()方法中,
chain.doFilter()前的一般是对request执行的过滤操作,
chain.doFilter后面的代码
一般是对response执行的操作。
过滤器一般用于登录权限验证、
资源访问权限控制、
敏感词汇过滤、
字符编码转换等等操作,
便于代码重用,
不必每个servlet中还要进行相应的操作。
83.Listener是什么?有什么作用?
监听器用于监听web应用中某些对象、
信息的创建、销毁、增加,修改,删除等
动作的发生,
然后作出相应的响应处理。
当范围对象的状态发生变化的时候,
服务器自动调用监听器对象中的方法。
常用于统计在线人数和在线用户,
系统加载时进行信息初始化,
统计网站的访问量等等。
分类:
按监听的对象划分,可以分为
ServletContext对象监听器
HttpSession对象监听器
ServletRequest对象监听器
按监听的事件划分
对象自身的创建和销毁的监听器
对象中属性的创建和消除的监听器
session中的某个对象的状态变化的监听器
84.你了解过Servlet3.0吗?
Servlet3.0相对于Servlet2.0来说
最大的改变是引入了Annotation注解
来取代xml配置,
用于简化web应用的开发和部署。
最主要几项特性:
1. 新增的注解支持:
该版本新增了若干注解,
用于简化 Servlet、
过滤器(Filter)
和监听器(Listener)的声明,
这使得 web.xml 部署描述文件
从该版本开始不再是必选的了。
2. 异步处理支持:
有了该特性,
Servlet 线程不再需要一直阻塞,
直到业务处理完毕才能再输出响应,
最后才结束该 Servlet 线程。
在接收到请求之后,
Servlet 线程可以将耗时的操作
委派给另一个线程来完成,
自己在不生成响应的情况下返回至容器。
针对业务处理较耗时的情况,
这将大大减少服务器资源的占用,
并且提高 并发处理速度。
3. 可插性支持:
熟悉 Struts2 的开发者一定会
对其通过插件的方式
与包括 Spring 在内的各种常用框架的整合
特性记忆犹新。
将相应的插件封装成 JAR 包并放在类路径下,
Struts2 运行时便能自动加载这些插件。
现在 Servlet 3.0 提供了类似的特性,
开发者可以通过插件的方式很方便的
扩充已有 Web 应用的功能,
而不需要修改原有的应用。
85.JSP和Servlet有哪些相同点和不同点?
JSP是Servlet技术的扩展,
本质上是Servlet的简易方式,
更强调应用的外表表达。
JSP编译后是"类servlet"。
Servlet和JSP最主要的不同点在于,
Servlet的应用逻辑是在Java文件中,
并且完全从表示层中的HTML里分离开来。
而JSP的情况是
Java和HTML可以组合
成一个扩展名为.jsp的文件。
在实际项目开发当中,
JSP侧重于视图,
Servlet主要用于控制逻辑。
86.如何获得高效的数据库逻辑结构?
从关系数据库的表中
删除冗余信息的过程
称为数据规范化,
是得到高效的关系型数据库表的逻辑结构
最好和最容易的方法。
规范化数据时应执行以下操作:
1.将数据库的结构精简为最简单的形式
2.从表中删除冗余值
3.标识所有依赖与其他数据的数据
规范化过程有几个阶段,
分别称作第一范式(1NF)、
第二范式(2NF)、
第三范式(3NF)、
第四范式(4NF)
以及第五范式(5NF)。
对于所有的实际应用,
3NF已经足够了。
87.数据库三范式是什么?
第一范式(1NF):
字段具有原子性,不可再分。
所有关系型数据库系统
都满足第一范式)
数据库表中的字段都是单一属性的,
不可再分。
例如,姓名字段,
其中的姓和名必须作为一个整体,
无法区分哪部分是姓,
哪部分是名,
如果要区分出姓和名,
必须设计成两个独立的字段。
第二范式(2NF):
第二范式(2NF)是在第一范式(1NF)的基础上
建立起来的,即满足第二范式(2NF)
必须先满足第一范式(1NF)。
要求数据库表中的每个实例
或行必须可以被惟一地区分。
通常需要为表加上一个列,
以存储各个实例的惟一标识。
这个惟一属性列被
称为主关键字或主键。
第二范式(2NF)要求实体的属性
完全依赖于主关键字。
所谓完全依赖是指不能存在
仅依赖主关键字一部分的属性,
如果存在,
那么这个属性和主关键字的这一部分
应该分离出来形成一个新的实体,
新实体与原实体之间是一对多的关系。
为实现区分通常需要为表加上一个列,
以存储各个实例的惟一标识。
简而言之,
第二范式就是非主属性
非部分依赖于主关键字。
第三范式(3NF)
是在第二范式的基础上建立起来的,
即满足第三范式(3NF)
必须先满足第二范式(2NF)。
第三范式(3NF)要求
非主关键字不能依赖于
其他非主关键字。
即非主关键字之间
不能有函数(传递)依赖关系.
即不能从一个表的某个字段
推出该表的另一个字段。
满足三范式的设计,
基本可以解决数据冗余、
插入异常、
更新异常、
删除异常等数据存储问题。
88.SQL语句分为哪几种?
SQL语句主要可以划分为以下几类:
DDL(Data Definition Language):
数据定义语言,
定义对数据库对象(库、表、列、索引)的操作。
包括:
CREATE、
DROP、
ALTER、
RENAME、
TRUNCATE等
DML(Data Manipulation Language):
数据操作语言,
定义对数据库记录的操作。
包括:
INSERT、
DELETE、
UPDATE、
SELECT等
DCL(Data Control Language):
数据控制语言,
定义对数据库、表、字段、
用户的访问权限和安全级别。
包括:
GRANT、
REVOKE等
Transaction Control:
事务控制
包括:
COMMIT、
ROLLBACK、
SAVEPOINT等
89. Delete、truncaate、drop都是删除语句,它们有什么分别?
delete 属于DML语句,
删除数据,
保留表结构,
需要commit,
可以回滚,
如果数据量大,
很慢。
truncate 属于DDL语句,
删除所有数据,
保留表结构,
自动commit,
不可以回滚,
一次全部删除所有数据,
速度相对较快。
Drop属于 DDL语句,
删除数据和表结构,
不需要commit,
删除速度最快。
90.Where和having都是条件筛选关键字,它们有什么分别?
1.Where语句是一条一条从磁盘读取的,
然后进行判断,
满足条件的存放到内存,
不满足忽略,
而having是将所有的数据读入内存中,
然后在内存内部逐条判断,
不满足直接删除
where是判断数据从磁盘
读入内存的时候,
having是判断分组
统计之前的所有条件
2.having子句中可以使用字段别名,
而where不能使用
3.having能够使用统计函数,
但是where不能使用
4.where 后不能跟聚合函数,
因为where执行顺序大于聚合函数。
5.having 是筛选组
而where是筛选记录
注意:HAVING用于应被用于WHERE子句的条目,
从我们开头的2条语句来看,
这样用并没有出错,
但是mysql不推荐。
而且也没有明确说明原因,
但是既然它要求,
我们遵循就可以了
91.如何提升数据查询的效率?
1.首先检查表的结构是否合理,
因为采用多表查询的时候,
看主外键的引用关系是否适当.
如果不适当则重新设置表结构.
如果是应用中的系统,
则不需要更改表的字段,
只更改主外键关系.
如果数据库中有较多的数据,
还应采用索引提高查询效率.
2.利用索引(index)
对查询进行优化,
index可以避免对表数据的全面扫描,
当你以某个字段建立一个索引的时候,
数据库就会生成一个索引页,
索引页不单单保存索引的数据,
还保存了索引在数据库的
具体的物理地址,
能够很快的定位查找到要找的记录
3. 如果表的列很少,
不适合建索引.
表数据很少查询,
而经常做insert、delete、update动作,
不适合建所以。
因为Oracle需要对索引额外维护。
建立索引后,select会快,
当执行过多次的insert,delete,update后,
会出现索引碎片,
影响查询速度,我
们应该对索引进行重组
(即drop掉索引重新create)
4.索引的类型分为:
B-树索引:
适合于大量的增、删、改,
大多数数据的索引默认类型。
位图索引:
适合于决策支持系统
HASH索引、分区索引等。
92.什么是数据库事务?
事务是作为一个逻辑单元
执行的一系列操作,
要么一起成功,要么一起失败。
一个逻辑工作单元必须有四个属性,
称为 ACID:
原子性、
一致性、
隔离性
持久性
属性,
只有这样才能成为一个事务。
原子性 :
事务必须是原子工作单元;
对于其数据修改,
要么全都执行
,要么全都不执行。
一致性 :
事务在完成时,
必须使所有的数据都保持一致状态。
在相关数据库中,
所有规则都必须应用于事务的修改,
保持所有数据的完整性。
事务结束时,
所有的内部数据结构
(如 B 树索引或双向链表)
都必须是正确的。
隔离性 :
由并发事务所作的修改
必须与任何其它并发事务
所作的修改隔离。
事务查看数据时数据所处的状态,
要么另一并发事务修改它之前的状态,
要么是另一事务修改它之后的状态,
事务不会查看中间状态的数据。
这为可串行性,
因为它能够重新装载起始数据,
并且重播一系列事务,
以使数据结束时的状态
与原始事务执的状态相同。
持久性 :
事务完成之后,
它对于系统的影响是永久性的。
该修改即使出现系统故障也将一直保持。
93.什么是数据库事务的隔离级别?
多个线程开启各自事务操作数据库中数据时,数
据库系统要负责隔离操作,
以保证各个线程在获取数据时的准确性。
数据库共定义了四种隔离级别:
Serializable:(串行化)
可避免脏读、
不可重复读、
虚读情况的发生
Repeatable read:(可重复读)
可避免脏读、
不可重复读情况的发生。
Read committed:(读已提交)
可避免脏读情况发生。
Read uncommitted:(读未提交)
最低级别,
以上情况均无法保证。
94.如何删除表中的重复数据,只保留一条记录?
1、查找表中多余的重复记录,
重复记录是根据单个字段(peopleId)来判断
select * from people
where peopleId in (
select peopleId from people
group by peopleId
having count(peopleId) > 1
)
2、删除表中多余的重复记录,
重复记录是根据单个字段(peopleId)来判断,
只留有rowid最小的记录
delete from people
where peopleName in (
select peopleName from people
group by peopleName
having count(peopleName) > 1
) and peopleId not in (
select min(peopleId) from people
group by peopleName
having count(peopleName)>1
)
3、查找表中多余的重复记录(多个字段)
select * from vitae a
where (a.peopleId,a.seq) in (
select peopleId,seq from vitae
group by peopleId,seq
having count(*) > 1
)
4、删除表中多余的重复记录(多个字段),只留有rowid最小的记录
delete from vitae a
where (a.peopleId,a.seq) in (
select peopleId,seq from vitae
group by peopleId,seq
having count(*) > 1
) and rowid not in (
select min(rowid) from vitae
group by peopleId,seq
having count(*)>1
)
5、查找表中多余的重复记录(多个字段),不包含rowid最小的记录
select * from vitae a
where (a.peopleId,a.seq) in (
select peopleId,seq from vitae
group by peopleId,
seq having count(*) > 1
)
and rowid not in (
select min(rowid) from vitae
group by peopleId,
seq having count(*)>1
)
6.消除一个字段的左边的第一位:
update tableName set
[Title]=Right([Title],(len([Title])-1))
where Title like '村%'
7.消除一个字段的右边的第一位:
update tableName set
[Title]=left([Title],(len([Title])-1))
where Title like '%村'
8.假删除表中多余的重复记录(多个字段),
不包含rowid最小的记录
update vitae set ispass=-1
where peopleId in (
select peopleId from vitae
group by peopleId
)
95.如何通过sql语句完成分页?
客户端通过传递start(页码),
PageSize(每页显示的条数)两个参数
去分页查询数据库表中的数据,
那我们知道MySql数据库提供了
分页的函数limit m,n,
但是该函数的用法和我们的需求不一样,
所以就需要我们根据实际情况
去改写适合我们自己的分页语句,
具体的分析如下:
比如:
查询第1条到第10条的数据的sql是:
select * from table limit 0,10;
对应我们的需求就是查询第一页的数据:
select * from table limit (1-1)*10,10;
查询第10条到第20条的数据的sql是:
select * from table limit 10,20;
对应我们的需求就是查询第二页的数据:
select * from table limit (2-1)*10,10;
查询第20条到第30条的数据的sql是:
select * from table limit 20,30;
对应我们的需求就是查询第三页的数据:
select * from table limit (3-1)*10,10;
二:通过上面的分析,
可以得出符合我们自己需求的分页
sql格式是:
select * from table limit (start-1)*PageSize,PageSize;
其中start是页码,
PageSize是每页显示的条数。
96.JDBC操作数据库的步骤 ?
1、加载数据库驱动
2、创建并获取数据库链接
3、创建jdbc statement对象
4、设置sql语句
5、设置sql语句中的参数(使用preparedStatement)
6、通过statement执行sql并获取结果
7、对sql执行结果进行解析处理
8、释放资源(resultSet、preparedstatement、connection)
97.JDBC中的Statement 和PreparedStatement的区别?
Java提供了
Statement、
PreparedStatement
CallableStatement
三种方式来执行查询语句,
其中 Statement 用于通用查询,
PreparedStatement 用于执行参数化查询,
而 CallableStatement则是用于存储过程。
关于PreparedStatement接口,
需要重点记住的是:
1. PreparedStatement可以写参数化查询,
比Statement能获得更好的性能。
2. 对于PreparedStatement来说,
数据库可以使用已经编译过
及定义好的执行计划,
这种预处理语句查询
比普通的查询运行速度更快。
3. PreparedStatement可以阻止常见的
SQL注入式攻击。
4. PreparedStatement可以写动态查询语句
5. PreparedStatement与
java.sql.Connection对象是关联的,
一旦你关闭了connection,
PreparedStatement也没法使用了。
6. “?” 叫做占位符。
7. PreparedStatement查询
默认返回FORWARD_ONLY的ResultSet,
你只能往一个方向移动结果集的游标。
当然你还可以设定为其他类型的
值如:”CONCUR_READ_ONLY”。
8. 不支持预编译SQL查询的JDBC驱动,
在调用connection.prepareStatement(sql)的时候,
它不会把SQL查询语句发送给数据库做预处理,
而是等到执行查询动作的时候
调用executeQuery()方法时
才把查询语句发送个数据库,
这种情况和使用Statement是一样的。
9. 占位符的索引位置从1开始而不是0,
如果填入0会导致
java.sql.SQLException invalid column index异常。
所以如果PreparedStatement有两个占位符,
那么第一个参数的索引时1,
第二个参数的索引是2.
98.说说数据库连接池工作原理和实现方案?
一般来说,Java应用程序访问数据库的过程是:
1.装载数据库驱动程序;
2.通过jdbc建立数据库连接;
3.访问数据库,执行sql语句;
4.断开数据库连接。
程序开发过程中,存在很多问题:
首先,
每一次web请求都要建立一次数据库连接。
建立连接是一个费时的活动,
每次都得花费0.05s~1s的时间,
而且系统还要分配内存资源。
这个时间对于一次或几次数据库操作,
或许感觉不出系统有多大的开销。
可是对于现在的web应用,
尤其是大型电子商务网站,
同时有几百人甚至几千人在线是很正常的事。
在这种情况下,
频繁的进行数据库连接操作
势必占用很多的系统资源,
网站的响应速度必定下降,
严重的甚至会造成服务器的崩溃。
其次,对于每一次数据库连接,
使用完后都得断开。
否则,如果程序出现异常而未能关闭,
将会导致数据库系统中的内存泄漏,
最终将不得不重启数据库
“数据库连接”是一种稀缺的资源,
为了保障网站的正常使用,
应该对其进行妥善管理。
其实我们查询完数据库后,
如果不关闭连接,
而是暂时存放起来,
当别人使用时,
把这个连接给他们使用。
就避免了一次建立数据库
连接和断开的操作时间消耗。
数据库连接池的基本思想:
就是为数据库连接建立一个“缓冲池”。
预先在缓冲池中放入一定数量的连接,
当需要建立数据库连接时,
只需从“缓冲池”中取出一个,
使用完毕之后再放回去。
我们可以通过设定连接池最大连接数
来防止系统无尽的与数据库连接
99.execute,executeQuery,executeUpdate的区别是什么?
在jdbc中有3种执行sql的语句分别是
execute,
executeQuery
executeUpdate
ResultSet executeQuery(String sql);
执行SQL查询,并返回ResultSet 对象。
方法executeQuery
用于产生单个结果集(ResultSet)的语句,
例如 SELECT 语句。
被使用最多的执行 SQL 语句的方法。
这个方法被用来执行 SELECT 语句,
它几乎是使用最多的 SQL 语句。
但也只能执行查询语句,
执行后返回代表查询结果的ResultSet对象。
2.int executeUpdate(String sql);
可执行增,删,改,
返回执行受到影响的行数。
方法executeUpdate
用于执行 INSERT、UPDATE 或 DELETE 语句
以及 SQL DDL(数据定义语言)语句,
例如 CREATE TABLE 和 DROP TABLE。
INSERT、UPDATE 或 DELETE 语句的效果
是修改表中零行或多行中的一列或多列。
executeUpdate 的返回值是一个整数(int),
指示受影响的行数(即更新计数)。
对于 CREATE TABLE 或 DROP TABLE 等
不操作行的语句,
executeUpdate 的返回值总为零。
3.boolean execute(String sql);
可执行任何SQL语句,
返回一个布尔值,
表示是否返回ResultSet 。
可用于执行任何SQL语句,
返回一个boolean值,
表明执行该SQL语句是否返回了ResultSet。
如果执行后第一个结果是ResultSet,
则返回true,否则返回false。
但它执行SQL语句时比较麻烦,
通常我们没有必要使用execute方法
来执行SQL语句,
而是使用executeQuery或executeUpdate更适合,
但如果在不清楚SQL语句的类型时
则只能使用execute方法
来执行该SQL语句了。
100.Statement中的setFetchSize和setMaxRows方法有什么用处
setMaxRows可以用来限制返回的数据集的行数。
当然通过SQL语句也可以实现这个功能。
比如在MySQL中我们可以用
LIMIT条件来设置返回结果的最大行数。
setFetchSize理解起来就有点费劲了,
因为你得知道Statement
和ResultSet是怎么工作的。
当数据库在执行一条查询语句时,
查询到的数据是在数据库的缓存中维护的。
ResultSet其实引用的是数据库中缓存的结果。
假设我们有一条查询返回了100行数据,
我们把fetchSize设置成了10,
那么数据库驱动每次只会取10条数据,
也就是说得取10次。
当每条数据需要处理的时间比较长的时候
并且返回数据又非常多的时候,
这个可选的参数就变得非常有用了。
我们可以通过Statement来
设置fetchSize参数,
不过它会被ResultSet对象
设置进来的值所覆盖掉。
网友评论