单例类:
保证封装性良好:private修饰类成员变量
就是指只能够创建一个实例的类,
怎么做到这一点:也就是说这个构造器是只能够用一次,
用private修饰这个构造器,这个就可以防止其他类来访问
这个类的构造器,提供一个public方法,让外部来访问这个类的成员
因为只创建一个对象,所以通过判断这个对象
是否已经存在null
要求:写一个只能创建一个学生对象的学生类。
有学习的行为,以及性别,年龄等属性
接下来就是demo
*/
class Single{
private static Single instance;//使用类变量来缓存实例
private static int age;
private static String sex;
private Single(){}
//判断是否已经存在对象,虽然说是只能创建一个对象,但是这个对象的属性却还是可以改变的
public static Single getSingleInstance(int age,String sex){
if(instance == null){
instance = new Single();
return instance;
}
else{
Single.age = age;
Single.sex = sex;
return instance;
}
}
public void show(){
System.out.println("我是一个热爱学习的学生!");
System.out.println("age: "+age+"----sex:"+sex);
}
}
public class SingleDemo{
public static void main(String[] args){
Single s1 = Single.getSingleInstance(18,"man");//0 null 因为对象没有创建,就没有属性
s1.show();
Single s3 = Single.getSingleInstance(19,"woman");
System.out.println("----------------------");
System.out.println(s1 == s3);
System.out.println("----------------------");
s3.show();
}
}
this指针:this是封装在某个定义里面的变量,还是非静态变量
this指针其实是类的非静态成员,一个时刻时间jvm只会对一个this引用的对象进行处理,同类的其他对象是不会进行处理的
当前的this所引用的对象就是jvm正在处理的,而且运行到其他时间,this引用的对象也会是不同的。
下面证明:
class Cow{
public int id;
class CowLeg{
CowLeg(){}
void show(){
System.out.println(id);
}
}
}
这里内部类可以访问外部类的实例变量,是非静态成员访问非静态成员,说明是非静态的
又因为一个类中如果有多个组合(对象),那么这个this会随着对象的引用发生变化,可见jvm在这个时间内,只会处理一个this引用的对象。
不考虑外部类的调用,可以知道的是,jvm只会处理一个对象,就算是寄生在外部类中,这个外部类也不需要做任何处理
在main方法开始之前,所有的类都会编译生成class文件
但是只有使用的类的class才会被加载
先加载父类的静态成员并赋值初始化和静态初始化块 看顺序
然后是子类,这里在进行类的加载的时候就会执行,给静态成员分配内存
这里包括了静态初始化块直接从硬盘读取到内存中
从main()方法开始
1.父类静态成员和静态初始化快,按在代码中出现的顺序依次执行。
2.子类静态成员和静态初始化块,按在代码中出现的顺序依次执行。
3. 父类的实例成员和实例初始化块,按在代码中出现的顺序依次执行。
4.执行父类的构造方法。
5.子类实例成员和实例初始化块,按在代码中出现的顺序依次执行。
6.执行子类的构造方法。
类的加载过程:
详细请看网址:
http://wenku.baidu.com/link?url=tThHWezvlElec7tCleQ5xlUs1JSWYrE7NlGy24piaitEgfRh-Hm6cz8-UsfH6WBIWQwZ0oTvjvFICQszhcbcoeMPrqXfwxSRo7J7prUrRlG
http://blog.csdn.net/ol_beta/article/details/6793884
然后值得注意的是:
如果在调用类的对象时,该类已经加载一遍了,下次调用
的时候就不不会加载该类的静态成员了。
/*
* 集合的由来:
* 我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储。
* 而要想存储多个对象,就不能是一个基本的变量,而应该是一个容器类型的变量,在我们目前所学过的知识里面,有哪些是容器类型的呢?
* 数组和StringBuffer。但是呢?StringBuffer的结果是一个字符串,不一定满足我们的要求,所以我们只能选择数组,这就是对象数组。
* 而对象数组又不能适应变化的需求,因为数组的长度是固定的,这个时候,为了适应变化的需求,Java就提供了集合类供我们使用。
*
* 数组和集合的区别?
* A:长度区别
* 数组的长度固定
* 集合长度可变
* B:内容不同
* 数组存储的是同一种类型的元素
* 而集合可以存储不同类型的元素
* C:元素的数据类型问题
* 数组可以存储基本数据类型,也可以存储引用数据类型
* 集合只能存储引用类型
*
* 刚说过集合是存储多个元素的,但是呢,存储多个元素我们也是有不同需求的:比如说,我要这多个元素中不能有相同的元素,
* 再比如说,我要这多个元素按照某种规则排序一下。针对不同的需求,Java就提供了不同的集合类,这样呢,Java就提供了很多个集合类。
* 这多个集合类的数据结构不同,结构不同不重要的,重要的是你要能够存储东西,并且还要能够使用这些东西,比如说判断,获取等。
* 既然这样,那么,这多个集合类是有共性的内容的,我们把这些集合类的共性内容不断的向上提取,最终就能形成集合的继承体系结构。
*
* 数据结构:数据的存储方式。
*
* Collection:是集合的顶层接口,它的子体系有重复的,有唯一的,有有序的,有无序的。(后面会慢慢的讲解)
*
* Collection的功能概述:
* 1:添加功能
* boolean add(Object obj):添加一个元素
* boolean addAll(Collection c):添加一个集合的元素
* 2:删除功能
* void clear():移除所有元素
* boolean remove(Object o):移除一个元素
* boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有) 一个就可以
* 就是说如果你没有c中的全部元素只有一部分,移除了也是可以的
* 3:判断功能
* boolean contains(Object o):判断集合中是否包含指定的元素
* boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)所有
* boolean isEmpty():判断集合是否为空
* 4:获取功能
* Iterator<E> iterator()(重点)
* 5:长度功能
* int size():元素的个数
* 面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?
* 6:交集功能
* boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
* 7:把集合转换为数组
* Object[] toArray()
*/
错误Conllection cn = new Conllection();
接口不能实例化
/*
* Iterator iterator():迭代器,集合的专用遍历方式
* Object next():获取元素,并移动到下一个位置。
* NoSuchElementException:没有这样的元素,因为你已经找到最后了。
* boolean hasNext():如果仍有元素可以迭代,则返回 true。
* Iterator it = c.iterator(); // 实际返回的肯定是子类对象,这里是多态
*/
实际上 集合Collection的遍历的方法 有很多 比如 foreach forEach forEachRemaining 还有普通for循环
还有while 等
但是我们只需要几个常用的简单的遍历 for(toArray方法) foreach 还有while迭代
值得注意的是 foreach 不能改变实际上的集合的值 也不能改变 如果在遍历的时候修改了集合的值
将会编译报错 ConcurrentModificationExceptin 异常
而while 是可以的其他的遍历方式不管
这里java8提供了一个很好的操作:Predicate
这个是风格函数式接口所以可以通过lambda表达式进行判断筛选出自定义条件的结果
比如syso(ele->((String)ele).contains("fenkuang")).
ArrayList:
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector:
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
LinkedList:
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
1.如果是可恢复错误,使用检查型异常;如果是编程错误,使用非检查型异常。
许多Java编程人员都很苦恼,到底是该选择检查型异常还是非检查型异常。
检查型异常是一种从语言到强制你编写代码的一种方式,可以保证你对错误条件提供异常处理代码
但同时也会引入大量杂乱的代码导致其不可读。如果你有恢复策略的话,这样做看起来似乎也可以。
2.在finally程序块中关闭或者释放资源
Java程序员对此都有所了解,在处理网络和IO类的时候,相当于一个标准。
在finally块中关闭资源, 在正常和异常执行的情况下,保证之前和稀缺资源的合
理释放,这由finally块保证。
从Java7开始,该语言有了一项更好的功能:资源管理自动化或者ARM块能实现这一功能。
尽管如此,我们仍然要记住在finally块中关闭资源,这是对于释放像FileDescriptors这类
应用在socket和文件编程的情况下的有限资源很重要的。
3.在堆栈跟踪中包含引起异常的原因
很多时候,当一个异常由另一个异常导致异常而被抛出的时候,
Java库和开放源代码会将一种异常包装成另一种异常。
这时,日志记录和打印根异常就变得非常重
要。Java异常类提供了 getCause()方法来检索导致异常的原因,
这些可以对异常根层次的原因提供更多的信息。
该Java实践对代码的调试或故障排除有很大的帮助。
另外,如果你要把一个异常包装成另一种异常,构造一个新异常就要传递源异常。
4.始终提供关于异常的有意义的完整信息、
异常信息非常重要,因为这是Java程序员最先看到的一个地方
在这里会有非常精确并且真实的信息,他们可以找到问题产生的根本原因。
5.避免过度使用检查型异常
检查型异常在强制执行方面有一定的优势,但同时它也破坏了代码,
通过掩盖业务逻辑使代码可读性降低。所以,Java程序员要注意,
不能过度使用检查型异常,你可以最大程度的减少这类情况,这样你会得到更精准、简洁的代码。
6.将检查型异常转为运行时异常
这个像是Spring之类的多数框架中,用来限制使用检查型异常的技术之一,大部分出自于JDBC的检查型异常,都被包装
进 DataAccessException中,而(DataAccessException)异常是一种非检查型异常。特定的异常限制到特定的模块,像
SQLException 放到DAO层,将运行时异常明确的说明然后抛到客户层。
7.记住对性能而言,异常代价比较高
异常代价比较高,还会让你的代码运行变得缓慢。
如果你有方法从ResultSet(结果集)中进行读取,这时常会抛出SQLException 异常而不会移
到下一元素,这将会比不抛出异常的正常代码执行速度慢很多。
因此Java程序员要最大限度的减少不必要的异常捕捉和移动。如果你能使用boolean变量
去表示执行结果,而不仅仅只是抛出和捕捉异常,你就有可能得到更简洁、更高性能的解决方案。
8.避免catch块为空
没有什么会比空的catch块更糟糕的了,因为它不仅隐藏了错误和异常,
还可能导致你的对象处于不可使用的状态。空的catch块没有任何意义,
如果你非常肯定异常不会继续以任何方式影响对象状态,在程序执行期间,
用日志记录错误依然是最好的方法。
9.使用标准异常
java程序员应该学会使用标准异常,而不是每次都创建自己的异常。
对于维护性和一致性,不管是现在还是以后,都是最好的选择。重用标准异常使代码更具可读性,因
为大部分Java开发人员对标准,像源自于JDK的RuntimeException 异常,IllegalStateException 异
常,IllegalArgumentException 异常或者NullPointerException异常,他们能一眼就知道每种异常的目的,而不
是在代码里查找或者在文档里查找用户定义的异常的目的。
10.记录任何方法抛出的异常
Java提供了throw和throws关键字来抛出异常,
在javadoc中用@throw记录任何方法可能会抛出的异常。
如果你编写API或者公共接口,这就变得非常重要。
任何方法抛出的异常都有相应的文档记录,
这样你就能下意识的提醒任何使用(该方法)的人。
异常处理原则:
1:函数内部如果抛出需要检测的异常,那么函数上必须要声明,
必须在函数内用trycatch捕捉
否则编译失败
2:如果调用到了声明异常的函数,要么trycatch要么throws,否则编译失败
3:什么时候catch,什么时候throws?
功能内部可以解决,用catch,解决不了用throws告诉调用者,由调用者解决
4:一个功能如果超出了多个异常,那么调用时,必须对应多个catch进行针对性处理
内部有几个需要检测的异常就抛几个异常,抛出几个就要catch几个
异常的注意事项:
1:子类在覆盖父类方法时,如果父类的方法抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类
2:如果父类抛出多个异常,那么子类只能抛出父类异常的子集;即子类fig父类只能抛出父类的异常或者子类或者子集
注意:如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛异常,只能捕获异常try catch
掌握基本命令1:
ddl:定义数据库对象
对数据库:
创建;
create database 数据库名
create table 表名()
create table 表名 as select * from 另外一个表名 这两个表结构数据完全相同
删除:
drop database 数据库名
drop 行 记录
drop 列 字段
truncate 表名 只是删除表里面的数据,但是标的结构就是行列没有改变
操作使用:
use 数据库名
修改:
alter table 表名这个需要和下面的一起使用
add 字段 类型。。可以多字段就是add多个列
modify 修改已经存在的 mysql不支持修改多个列一般是修改数据类型
rename 表名
change 修改列名 也不支持多个列名的修改
查看数据表(前提是进入了该数据库):
show tables
查看表中的结构:
desc 表名 前提同上
注意:数据库必须是没有存在的,已经存在就不同创建相同的。
在进行数据库操作之前,必须 先进行用户登录
mysql -uroot -p
没有设密码 所以 两次回车
sql语句不区分大小写。
DML语句:
插入:
insert into 表名(你要插入的列具体自己多练习)
在表名后面加上value(输入你要插入的值 )
修改语句:
update,通过where子句限定那些需要修改
set 列 = 值
update teacher_table
set teacher_name = 'zhubajie'
where teacher_id > 1;
delete from 语句
删除指定数据的记录( 行)同样用 where限定符
delete from student_table
where student_id > 2;
值得注意的是,但主表记录被从表记录参照的时候,主表记录不能被删除
只有当从表记录被全部删除的时候才能够删除主表的记录
或者:
定义外键的时候定义了主表记录和从表记录的级联删除on delete casade
或者用on delete set null用于指定当主表记录被删除时,从表记录外键列值被设为null
参照的理解:
所谓参照完整性,简单地说就是控制数据一致性,尤其是不同表之间关系的规则。
建立永久关联的目的就是利用关联表之间的制约机制互相参照,控制表间数据的一致性和完整性
这种制约机制会在用户执行插入、修改或删除记录等编辑记录的操作时,发挥其限制作用。
参照完整性有效限制了对表中数据的非法编辑。具体说参照完整性是指不允许在相关数据表中引用不存在的记录。
private 修饰成员变量
提供public 的get set方法
无参构造器
实现serializable接口
更加复杂的javabean:
EJB在企业开发中,需要可伸缩的性能和事务、安全机制,
这样能保证企业系统平滑发展,而不是发展到一种规模重新更换一套软件系统。
然后有提高了协议要求,就出现了Enterprise Bean。
既不是最简单的javabean 又不是复杂的ejb
就是POJO
POJO是普通的javabean,什么是普通,就是和EJB对应的。
总之,区别就是,你先判断是否满足javabean的条件,然后如果再实现一些要求
满足EJB条件就是EJB,否则就是POJO
对于普通的RowSet而言,就好像是一排人马,现在将他们通过查询,筛选出一些人,这些人被定义为RowSet,但是并不可能是复制一份
所以如果需要显示,必然需要一直把大门打开着,才能看到
这样比较麻烦,我要告诉别人,筛选的东西,还要一直打开,
所以有了离线的RowSet,就相当于拷贝了一份名单,交上去就好了
这里就读取到了内存中。但是如果修改这份名单,对于本来的名单是不会有用的,
所以同步的方法是acceptChanges方法
至于工厂模式
这里有RowSetFactory 他的机器FactoryProvider是提供工厂对象的
这个对象调用create某某RowSet方法就可以创建相对应的离线RowSet对象了,
可见这里面肯定包装了调用相对应的离线RowSet构造器
至于离线RowSet的分页查询:
目的就是减轻内存的负担的
也就是说,每次在ResultSet中间选定一组数据读取到内存中
不需要了,或者说用完了就释放掉,然后又读取下一组数据到内存中这样就可以避免了占用过多的内存的问题
驱动加载:
如果是建立web项目就需要复制驱动
建立在webroot目录下的web-int的lib目录下
用普通的java项目也需要复制驱动
项目名字--properties--java build path--add exeternal jars--选中你的jar包
简单地说就是把硬盘上的有用程序调到内存中的过程叫做加载 。
Class.forName(driver)
forName
public static Class<?> forName(String className)
throws ClassNotFoundException
返回与带有给定字符串名的类或接口相关联的 Class 对象
调用此方法等效于:
Class.forName(className, true, currentLoader)
其中 currentLoader 表示当前类的定义类加载器。
例如,以下代码片段返回命名为 java.lang.Thread 的类的运行时 Class 描述符。
Class t = Class.forName("java.lang.Thread")
调用 forName("X") 将导致命名为 X 的类被初始化。
所以这里driver会被初始化。
参数:
className - 所需类的完全限定名。
返回:
具有指定名的类的 Class 对象。
抛出:
LinkageError - 如果链接失败
ExceptionInInitializerError - 如果此方法所激发的初始化失败
ClassNotFoundException - 如果无法定位该类
--------------------------------------------------------------------------------
建立数据库连接:
DriverManager类可以加载在 "jdbc.drivers" 系统属性中引用的驱动程序类
java.sql
类 DriverManager
java.lang.Object
继承者 java.sql.DriverManager
public class DriverManagerextends Object
管理一组 JDBC 驱动程序的基本服务。
注:DataSource 接口是 JDBC 2.0 API 中的新增内容,它提供了连接到数据源的另一种方法。
使用 DataSource 对象是连接到数据源的首选方法。也就是说不是唯一的方法
作为初始化的一部分,DriverManager 类会尝试加载在 "jdbc.drivers" 系统属性中引用的驱动程序类。
应用程序不再需要使用 Class.forName() 显式地加载 JDBC 驱动程序。
当前使用 Class.forName() 加载 JDBC 驱动程序的现有程序将在不作修改的情况下继续工作。
在调用 getConnection 方法时,DriverManager 会试着从初始化时加载的那些驱动程序以及使用与当前
applet 或应用程序相同的类加载器显式加载的那些驱动程序中查找合适的驱动程序。
这允许用户定制由他们的应用程序使用的 JDBC Driver。例如,在 ~/.hotjava/properties 文件中,用户可以指定:
jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver
显示传参数:
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/select_test",
"root" , ""
);
定义为类的成员变量:
private String driver;
private String url;
private String user;
private String pass;
public void initParam(String paramFile)throws Exception{
Properties props = new Properties();
props.load(new FileInputStream(paramFile));
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("user");
pass = props.getProperty("pass");
}
Connection conn = DriverManager.getConnection(url,user,pass)
初始化函数initparam()
getProperty(String key)
用指定的键在此属性列表中搜索属性。
主要理解load和new FileInputStream 一个读取,一个获取ini文件的输入流
load(InputStream inStream)
从输入流中读取属性列表(键和元素对)
FileInputStream(File file)
通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。
这里的FileInputStream 是一个类通过这个类可以读取指定位置的文件
getconnection():
public static Connection getConnection(String url,
String user,
String password)
throws SQLException
试图建立到给定数据库 URL 的连接。DriverManager 试图从已注册的 JDBC 驱动程序集中选择一个适当的驱动程序。
//统一资源定位符
参数:
url - jdbc:subprotocol:subname 形式的数据库 url
user - 数据库用户,连接是为该用户建立的
password - 用户的密码
返回:
到 URL 的连接
抛出:
SQLException - 如果发生数据库访问错误
connection对象:
与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。
创建stmt对象
try(
Statement stmt = conn.createStatement())
{
建立结果集并遍历
通过execute...()执行sql语句
}
createStatement
Statement createStatement()
throws SQLException
创建一个 Statement 对象来将 SQL 语句发送到数据库。
不带参数的 SQL 语句通常使用 Statement 对象执行。
如果多次执行相同的 SQL 语句,使用 PreparedStatement 对象可能更有效。
使用返回的 Statement 对象创建的结果集在默认情况下类型为 TYPE_FORWARD_ONLY
并带有 CONCUR_READ_ONLY 并发级别。已创建结果集的可保存性可调用 getHoldability() 确定。
返回:
一个新的默认 Statement 对象
抛出:
SQLException - 如果发生数据库访问错误,或者在关闭的连接上调用此方法
try语句会进行显示的close调用
try{ }catch(){ },try里面放的是执行代码,如果在执行的时候出现问题
由catch进行捕获,捕获后可以分两种情况处理,一种是执行catch里的语句
可以自己写,也可以调用现成的,另一种是不作任何处理,直接抛出。
--------------------------------------------------------------------------------
查看api文档有很大的帮助
select语句的功能就是查询数据
是功能最丰富的语句
select语句可以使用算术运算符形成算数表达式
将列名看做变量
select teacher_id + 5
from teacher_table;
所有的id都加上5
select 3*5,20
from select table;
这里选择的是两个数据列3*5,20
别名: 紧跟数据列,中间以空格隔开 或者使用关键字as隔开
select teacher_id + 5 as "my'id"
from teacher_table;
如果别名中有'这个就要用双引号引起来 多个列名起别名中间以逗号隔开
也同样是可以给表名起别名的
可以使用函数
select concat(teacher_name, 'xx')
from teacher_table;
如果连接的是一个null则使得这个连接的结果也变为null使用这个函数,遇上了NULL也能串连起来,如:
SELECT CONCAT ('ab',null,'cd')
如果列名是一个常量
会把常量的结果算出来给指定where条件的列赋值
关于虚表:
没有任何意义,相当于一个占位符
除去重复行,distinct
作用是只要满足后面的字段的重复条件,不会管整条记录是否重复
比如:(1,a,b) (2,a,b)如果说这个a,b是表示distinct的判断条件
那么就会表示这两条记录相同,表示重复行
顾名思义
between and
and
or
in:
where 3 in(student_id,java_tacher)
选出student_id,java_tacher列值为3的记录
like: 像
%代表的是任意多个字符
_代表的是任意一个字符
'\'可以用来转义:加上强制的escape表示就是\没有转义的作用
比如where student_name like '\_%' escape '\'
这里的下划线就是下划线,选出所有以下划线开头的学生
但是如果没有加上escape '\' 表示的是以_开头的学生
where .. is null
order by
默认为升序排序加上desc为降序
where。。。
order by 列名 desc,列名
数据库函数:
暂时先记住几个函数:
ifnull(x1,x2):如果x1是null ,返回x2,否则返回x1
nullif(x1,x2):如果x1 == x2 返回null 否则返回x1
if(x1,x2,x3):如果x1是true 不等于0 不等于 null 返回x2 否则返回x3
isnull(x):x是否为null,null返回true 否则false
select if(isnull(student_name),'meiyoumingzi','youmingzi')
from student_table;
case函数:
两个用法:
select 列名1。。 ,case
when condition1 then result1
when condition2 then result2
else result
end
from...
select 列名,case value
when compare_value1 then result1
when compare_value2 then result2
else result
end
from...
分组函数:
avg():计算多行平均值,可以在变量列前家distinct或all关键字 数据类型必须是数值型
all用处不大,表明计算重复值,后面的函数也是一样的,distinct则是不计算重复值
select avg(ifnull(java_teacher,0))
from student_table
count():总数。
select count(distinct *)
from student_table
max,min():最大值最小值
select max(student_id)
from student_table
sum:求和
select sum(student_id)
from student_table
group by: 不能使用where子句进行多行过滤,只能使用have子句
select *
from student_table
group by java_teacher
have cout(*)>2
子查询是嵌套查询,就是select语句后面跟的还是一个select语句
多表连接查询就是查询不同表中的相同或者不同的数据
集合运算:
交:
intersect 语句 intersect select语句 下面一样 不过mysql暂时不支持交集运算可以通过多表连接查询实现join on
差:
minus 数据列的数量 类型相同才可以进行差集运算 不过mysql暂时不支持交集运算 可以通过 not in的方式实现
并:union 结果集的数据列必须和前面一个结果集的数据列一一对应 不过mysql暂时不支持交集运算
首先什么叫存储过程? //了解
存储过程(Stored Procedure)是在大型数据库系统中
一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中
用户通过指定存储过程的名字并给出参数
(如果该存储过程带有参数)来执行它。
本质上还是一些sql语句,同样是用来执行某些查询,修改操作的。
//和预编译是差不多的,效率比较高,因为只需要编译一次大部分的sql语句不需要再次编译,只有参数需要通过SetXXX给出具体的值
为什么要这个东西?本来就有一般的sql语句啊?
时间上:编译一次就可以了,和预编译的类似。
这样在前台方面不需要多次连接数据库
从响应时间上来说具有优势
安全上:程序容易出现bug,存储过程,只要数据库不出问题
基本上就没有问题。系统更加稳定
至于为什么会这样安全一些,还没有去深究
解释:当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete 时)
可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。
这些操作,如果用程序来完成,就变成了一条条的 SQL 语句,可能要多次连接数据库。
而换成存储,只需要连接一次数据库就可以了。
可指定用户对此存储过程有访问权
更强的适应性:由于存储过程对数据库的访问是通过存储过程来进行的
因此数据库开发人员可以在不改动存储过程接口的情况下对数据库进行任何改动
而这些改动不会对应用程序造成影响。
布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制
正因为如此才不会影响程序的效率,反而能提升。
总之,比较少的sql语句不需要存储过程,但是很多数据的时候,还是有效率区别的,不过现在的存储过程的优势不明显了
首先需要创建存储过程
create proc | procedure pro_name
({@参数数据类型} [=默认值] [output],
{@参数数据类型} [=默认值] [output],
....
)
as
SQL_statements
//起个别名
删除drop procedure procedurename;
同样进行八大步骤,加载驱动,创建数据库连接对象,创建执行sql语句的
对象,创建结果集,遍历结果集。这里面的执行sql语句的对象不再是stmt
而是CallableStatement对象 cstmt
用于执行 SQL 存储过程的接口。这里是实现类对象
CallableStatement cstmt = conn.prepareCall(sql);
这个实现类对象继承了接口的setXXX()方法,可以对存储过程设置参数
CallableStatement prepareCall(String sql,
int resultSetType,
int resultSetConcurrency,
int resultSetHoldability)
throws SQLException
创建一个 CallableStatement 对象,
调用存储过程的格式:cstmt = conn.prepareCall("{call 存储过程名(?,?,?)}");
该对象将生成具有给定类型和并发性的 ResultSet 对象。
此方法与上述 prepareCall 方法相同,但它允许重写默认结果集类型、结果集并发性类型和可保存性。
void setInt(String parameterName,
int x)
throws SQLException
将指定参数设置为给定 Java int 值。在将该值发送到数据库时,
驱动程序将它转换成一个 SQL INTEGER 值。
cstmt.setInt(1,4);
parameterIndex 表示的是sql语句中第几个"?"
这里表示的是存储过程中的第一个参数设为4(表中要存在)
为什么需呀传入参数,因为存储过程机油传入参数又有传出参数,传入用于参数传入相当于调用方法,传出是为了获取存储过程里的值。
void registerOutParameter(int parameterIndex,
int sqlType)
throws SQLException
按顺序位置 parameterIndex 将 OUT 参数注册为 JDBC 类型 sqlType。所有 OUT 参数都必须在执行存储过程前注册。
CallableStatement需要通过registerOutParameter()方法注册该参数。
比如:cstmt.registerOutParameter(3,TYPES.INTEGER);
表示第三个参数是int类型的
用cstmt的execute方法来执行过程。输出传出参数的值getXXX()方法
因为你创建存储过程的时候是又返回值得就像普通的方法一样,可以通过这个传出参数的位置返回你的结果
以默认的方式打开结果集是不可更新的
如果希望创建可以更新的结果集
必须传入额外的参数
记住这两个:ResultSet.TYPE_SCROLL_SENSITIVE
ResultSet_CONCUR_UPDATABLE
可更新的结果集需要以下两个条件
所有数据来自同一个表
选出的数据集必须包含主键列
注意几个方法:
指针移动方法:previous last next
absolute:将光标移动到此ResultSet对象的给定行号
UpdateSring():用String更新指定列
保存:updateRow();
getRow()获取当前编号
处理Blob二进制常对象
因为比较大,所以以二进制数据保存在数据库里面
getBinaryStream
InputStream getBinaryStream()
throws SQLException以流的形式获取此 Blob 实例指定的 BLOB 值。
返回:
包含 BLOB 数据的流
抛出:
SQLException - 如果访问 BLOB 值时发生错误
SQLFeatureNotSupportedException - 如果 JDBC 驱动程序不支持此方法
InputStream getBinaryStream(long pos,long length)
throws SQLException
返回包含部分 Blob 值的 InputStream 对象
该值从 pos 指定的字节开始,长度为 length 个字节。
getBytes
byte[] getBytes(long pos,int length)
throws SQLException
以 byte 数组的形式获取此 Blob 对象表示的全部或部分 BLOB 值。此 byte 数组包含从位置 pos 开始的 length 个连续字节。
参数:
pos - 要提取的 BLOB 值中第一个字节的顺序位置;第一个字节位于位置 1 处
length - 要复制的连续字节的数量;length 的值必须大于等于 0
返回:
一个字节数组,它包含此 Blob 对象指定的 BLOB 值中的 length 个连续字节(从位置 pos 处的字节开始)
抛出:
SQLException - 如果访问 BLOB 值时发生错误;如果 pos 小于 1 或 length 小于 0
SQLFeatureNotSupportedException - 如果 JDBC 驱动程序不支持此方法
Blob getBlob(int columnIndex)
throws SQLException
以 Java 编程语言中 Blob 对象的形式获取此 ResultSet 对象的当前行中指定列的值。
参数:
columnIndex - 第一个列是 1,第二个列是 2,……
返回:
表示指定列中的 SQL BLOB 值的 BLOB 对象
分析结果集:
掌握三个方法:
int getColumnCount();
String getColumnName(int column);
int getColumnType(int column);
首先事务,本质上就是逻辑的sql语句
一句或者多句
这里的事务,不可再分,也就是所,要么执行完要么放弃执行
执行完后会保存到底层数据库
怎么保存到底层数据库呢?
通过提交:
显示提交:就是调用commit方法
自动提交:事务没有打开,执行DDL 或者DCL 这两种语句会自动提交,或者是程序正常退出
为了保证事务能够要么执行完,要么不行,防止执行到了一半就报错,程序出错
事务提供了回滚 回滚需要设置中间点 savepoint
显示回滚:
rollBack
自动回滚:系统出错或者强行退出
这里显示与自动的理解:
事务本身存在,只是因为这个事务的模式没有打开,要打开就使用如下命令:
setAutoCommit(false);自动commit 关闭
所以提交到底层数据库,这里反正是要调用commit方法的,这里只是用事务与不用事务的区别
那么为什么需要事务,他的作用是什么?
事务是用来保存底层数据库的数据完整的重要手段
怎么保证?
就是通过commit 来实现的,不提交 中间修改如果出现问题就回滚,不提交就无法修改底层数据
这样就保证了数据的完整性
你会数据库的安装吗?
进入官网下载。按照如下网址进行操作即可:
http://jingyan.baidu.com/article/597035521d5de28fc00740e6.html
什么叫做数据库?
数据库就是按照数据结构来组织、存储和管理数据的仓库
换句话说:用来存储数据的一个存放空间。有自己的数据结构用作存储机制。
什么叫做jdbc?
就是数据库连接。可以想到接口,用作连接,这个java data basic connectivity就是
一种可以执行sql语句的java api.程序通过jdbc 这个api,连接到关系数据库,使用结构化查询语言
sql可以对数据库进行查询和更新操作。值得一提的是:对数据库的操作大部分是查询的,比如日常生活中的手机什么的,
都是看消息,查询,上网百度。一般是不会修改和删除的。
理解1:
这个jdbc也就是应用编程接口只是一个规范化的接口,不提供实现,这样就实现了跨数据库,也实现了跨平台,如果不同
公司对于数据库的要求不同,只需要他们自己实现这个应用编程接口。所以这个接口的实现类就是驱动。
理解2:
jdbc的驱动程序通常分为四种类型:
jdbc—odbc桥,最新版本java8已经不用
直接将jdbcapi映射到数据库特定的客户端api
支持三层结构的jdbc访问方式(这个东西暂时不去深究),主要用于applet阶段,通过applet访问数据库
我们要学习的是第四种驱动:纯Java的直接和数据库实例交互,这种驱动知道数据库的底层协议
odbc更加复杂,jdbc更加安全,所以odbc-jdbc被淘汰。
哪几种数据库?
网状型数据库
层次型数据库
关系数据库
面向对象数据库 这个还没广泛应用,但可能以后会使用广泛,毕竟面向对象
我们要学习的是理论最成熟,应用最广泛的关系数据库
理解3:
数据库不等于数据表,数据表是存储数据的逻辑单元,数据库包括数据表。
掌握基本命令1:
ddl:定义数据库对象
对数据库:
创建;
create database 数据库名
create table 表名()
create table 表名 as select * from 另外一个表名 这两个表结构数据完全相同
删除:
drop database 数据库名
drop 行 字段
drop 列(记录)
truncate 表名 只是删除表里面的数据,但是标的结构就是行列没有改变
操作使用:
use 数据库名
修改:
alter table 表名这个需要和下面的一起使用
add 字段 类型。。可以多字段就是add多个列
modify 修改已经存在的 mysql不支持修改多个列一般是修改数据类型
rename 表名
change 修改列名 也不支持多个列名的修改
查看数据表(前提是进入了该数据库):
show tables
查看表中的结构:
desc 表名 前提同上
注意:数据库必须是没有存在的,已经存在就不同创建相同的。
在进行数据库操作之前,必须 先进行用户登录
mysql -uroot -p
没有设密码 所以 两次回车
MySQL的存储机制:
MuISAM:早期默认的存储机制,渐渐淘汰。
InnoDB:提供事物安全的存储机制,相对上面的存储机制而言是优点。我们要用的是这个。
sql语句不区分大小写。
关于表的理解:
数据库一般术语中记录是一行,字段是一列,记录和字段在分别对应关系数据库中的属性和元组
接下来学了数据库的约束:
只要学习四种:
非空: not null
唯一: unique 列不重复的意思
主键:primary key指定该列的值可以唯一的标识该条记录 但是主键其实可以对应多个列的
只是一个表其实只能有一个主键,但这个主键可以对应多个列id - 人 书名 出版社 版本 ---书籍
外键:foreign key指定该记录从属于主表中的一条记录。主要用于保证参照完整性
对于外键的理解,在这里我也举个例子。假设有两个表,学生表(学号,姓名,年龄,性别,专业编号),
专业信息表(专业编号,专业名称,专业备注信息)。学生表中主键是学号,专业信息表中主键是专业编号。
学生表中的非主属性专业编号恰好是专业信息表中的主键。我们就称这个专业编号是学生表的外键。
像这样,一个表的非主属性是另一个表的主属性,该非主属性就是外键。
数据库的约束有三种,实体完整性约束、参照完整性约束和用户自定义约束。
1.实体完整性约束指的是主键不能为空,如果主键为空了还怎么唯一标识一条记录。
2.参照完整性约束,即外键的约束,某一外键的值必须在它引用的主键字段中存在。
如,学生表中专业编号属性的值,必须都存于专业信息表中的专业编号属性中。
想一想也就明白了,一个学生(大学生)怎么可能属于一个不存在的专业。
3.用户自定义完整性约束,指的是一些用户自己设定的约束,例如字段是否可以为空
,字段值的取值范围(如:人的性别只能取男、女)。
约束同样有drop操作 但是not null 直接就是 null就可以了 可以通过alter add一下,或者create的时候定义的时候加进去
具体的话通过实践记住
索引:
索引是存放在模式中的一个数据库对象,虽然索引总是从属于数据表,但也和数据表一样属于数据库对象
创建索引的目的是为了加速对表的查询。
索引作为数据库对象是在数据字典中单独存放的,但是不是单独存在的,从属于表
这里的模式通过百度可以知道,作用和之前学过的包类似
创建索引:
自动:在表上定义外键,主键,唯一约束时,系统会为该数据自动创建对应的索引
手动:create index。。。
删除:
数据表删除则删除
drop index。。
索引的好处:
加速查询,类似书本的目录,这样减少了磁盘io
坏处;
存储索引需要一定的磁盘空间
视图:
首先:甚是视图?
视图可以理解为不能存储数据的数据表,也就是一个或者多个数据表中数据的逻辑显示。
这样一来,视图只能被查询,一般不修改,可以通过with check option字句强制不允许改变视图。
视图的本质就是一条被命名的sql查询语句,这条语句可以很复杂
好处:
可以限制对数据的访问
理解:就是只看不改
是复杂的查询变得简单:
有些数据是经常要用到的,要查询的,那么直接把这些查询的结果做成视图
就可以免去再次使用时一系列的复杂查询过程
提供了对数据的不同显示
不同的用户以不同的方式看到不同或相同的数据集
因为视图可以联系到多个数据表
DML语句:
插入:
insert into 表名(你要插入的列具体自己多练习)
在表名后面加上value(输入你要插入的值 )
修改语句:
update,通过where子句限定那些需要修改
set 列 = 值
update teacher_table
set teacher_name = 'zhubajie'
where teacher_id > 1;
delete from 语句
删除指定数据的记录( 行)同样用 where限定符
delete from student_table
where student_id > 2;
值得注意的是,但主表记录被从表记录参照的时候,主表记录不能被删除
只有当从表记录被全部删除的时候才能够删除主表的记录
或者:
定义外键的时候定义了主表记录和从表记录的级联删除on delete casade
或者用on delete set null用于指定当主表记录被删除时,从表记录外键列值被设为null
参照的理解:
所谓参照完整性,简单地说就是控制数据一致性,尤其是不同表之间关系的规则。
建立永久关联的目的就是利用关联表之间的制约机制互相参照,控制表间数据的一致性和完整性
这种制约机制会在用户执行插入、修改或删除记录等编辑记录的操作时,发挥其限制作用。
参照完整性有效限制了对表中数据的非法编辑。具体说参照完整性是指不允许在相关数据表中引用不存在的记录。
索引:
索引是存放在模式中的一个数据库对象,虽然索引总是从属于数据表,但也和数据表一样属于数据库对象
创建索引的目的是为了加速对表的查询。
索引作为数据库对象是在数据字典中单独存放的,但是不是单独存在的,从属于表
索引属于内模式。
索引保存了表中的排序列,并记录了排序列的地址。了解:内模式是数据物理结构和存储方式的描述,是数据在数据库内部的表示方式。
创建索引:
自动:在表上定义外键,主键,唯一约束时,系统会为该数据自动创建对应的索引
手动:create index。。。
删除:
数据表删除则删除
drop index。。
索引的好处:
加速查询,类似书本的目录,这样减少了磁盘io
坏处;
存储索引需要一定的磁盘空间
空间足够,一般没有关系
视图:
首先:甚是视图?
视图可以理解为不能存储数据的数据表,也就是一个或者多个数据表中数据的逻辑显示。
就是虚表
这样一来,视图只能被查询,一般不修改,可以通过with check option字句强制不允许改变视图。
视图的本质就是一条被命名的sql查询语句,这条语句可以很复杂
好处:
可以限制对数据的访问
理解:就是只看不改
是复杂的查询变得简单:
有些数据是经常要用到的,要查询的,那么直接把这些查询的结果做成视图
就可以免去再次使用时一系列的复杂查询过程
提供了对数据的不同显示
不同的用户以不同的方式看到不同或相同的数据集
因为视图可以联系到多个数据表
create or replace view 视图名
as
subquery//select teacher_namel,teacher_pass from teacher_table
with check option
drop...
直接对比普通的statement
public void insertUseStatement()throws Exception{
//System.currentTimeMillis()表示的是当前所用的时间
long start = System.currentTimeMillis();
try(
//获取数据库连接通过DriverManager类的getConnection(url,user,pass)方法
Connection conn = DriverManager.getConnection(url,user,pass);
//创建Statement对象执行sql语句
Statement stmt = conn.createStatement())
{
//元素名字可以带上'号
for(int i = 0;i < 100;i++){
stmt.executeUpdate("insert into student_table values("
+ "null,'name','M' , 1 )");
}
System.out.println("使用Statement耗时:" + (System.currentTimeMillis() - start));
}
}
public void insertUsePrepare()throws Exception{
long start = System.currentTimeMillis();
try(
//获取数据库连接通过DriverManager类的getConnection(url,user,pass)方法
Connection conn = DriverManager.getConnection(url,user,pass);
//创建PreparedStatement对象执行sql语句
PreparedStatement pstmt = conn.prepareStatement(
"insert into student_table values(null,'x',?,1)"))
{
for(int i = 0;i < 100;i++){
pstmt.setLong(1 , 11);
pstmt.executeUpdate();
}
System.out.println("使用PreparedStatement耗时:"
+ (System.currentTimeMillis() - start));
}
}
这个预编译的好处:
性能更好在内存上,直接保存一次的大部分数据就可以了,只需要通过?这个占位符来传入相应的参数
节省了多次编译所用的时间
不需要拼接字符串直接和命令行编写一样
防止了sql语句注入
sql语句注入就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,
而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,
其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。
根据相关技术原理,SQL注入可以分为平台层注入和代码层注入。
前者由不安全的数据库配置或数据库平台的漏洞所致;后者主要是由于程序员对输入未进行细致地过滤,
从而执行了非法的数据查询。基于此,SQL注入的产生原因通常表现在以下几方面:
①不当的类型处理;②不安全的数据库配置;③不合理的查询集处理;④不当的错误处理;⑤转义字符处理不合适;⑥多个提交处理不当。
如何防止?
http://www.iteye.com/topic/617072
这些东西多了解一下就行了
占位符的理解:
就是用来占一个位置的,这里的位置是指参数的位置,也就是说这个占位符是代表的参数
这个参数具体通过setXXX(int Index,XXX vakue)方法来传入具体的参数