在for循环中,当执行continue语句时,i++还是会执行,continue语句只代表此次循环结束,i还是会累加,并继续执行下次循环。
引用格式: 外部类名.this
格式:外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
例: outer.inner in = new outer().new inner();
比如:private 将内部类在外部类中进行封装。
static 内部类就具备了static的特性。
当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。
new 外部类名.内部类名().方法名();
例: new outer.inner().function();
因为内部类为static的,所以不必建立外部类对象,只要调用外部类类名就可,如何建立内部类对象,通过.即可访问方法了。
外部类名.内部类名().方法名();
例: outer.inner().function();
因为内部类与方法都是static的,所以不必建立对象,可以通过类名直接访问。
当内部类中定义了静态成员,该内部类必须是static的。
当外部类中的静态方法访问内部类时,内部类也必须是static的。
因为内部事物在使用外部事物的内容。
内部类定义在局部时需要注意2点: 比如定义在一个方法内
一是不可以被成员修饰符修饰。
二是可以直接访问外部类中的成员,因为还持有外部类中的引用,但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量。
请注意:有stringbuffer和stringbuilder类,以后开发,建议使用stringbuilder类。
stringbuilder的好处: 1、提高效率;2、简化书写;3、提高安全性。
1. character中的常用方法:
2. integer中的常用方法:
string和stringbuilder的底层都是使用字符数组来保存数据,其中的区别如下:
string是不可变的: string的底层字符数组如此所示:private final char value[];
final表示该内置的数组被赋值后不能改变地址值
private 修饰,而且没有提供set方法来修改,意味着一旦创建对象后就不能修改了
stringbuilder是可以被改变的: stringbuilder的底层字符数组如此所示: char[] value;
没有使用final和private修饰,表示stringbuilder可以后期修改。
怎么选取使用哪个?
保存字符数据 ------------> string
反复修改数据(拼接,删除,修改)------------>stringbuilder
int类型和string类型是能相互转换的,转换方法如下:
int à string :
可以直接拼接字符串,如 5 + “”;
可以通过string类中的一个方法:public static string valueof(int i)
string à int
可以通过integer类中的一个方法:public static int parseint(string s)
自动装箱:把基本数据类型转换为对应的包装类类型
public static integer valueof(int i)
自动拆箱:把包装类类型转换为对应的基本数据类型
public int intvalue();
jdk1.7版本中,接口里只能定义抽象方法,在jdk1.8版本后接口中可以定义普通方法了
a. date类是一个与时间相关的类,现主要有2个构造方法和2个普通方法需掌握:
b. simpledateformat类的概述和使用:simpledateformat是一个以与语言环境有关的方式来格式化和解析日期的具体类。该类中主要有3个功能需掌握,一个是对日期进行格式化(日期 -> 文本),能将上述date类中的不规则日期格式变成我们想要的格式进行输出;还有一个能将我们输入的文本进行解析(文本 -> 日期),能将我们输入不同格式的文本进行解析,返回一个date类型的值;第三个是当创建该类对象时没有使用构造函数赋默认格式时可以使用applypattern方法赋予指定格式。
date d = new date();
simpledateformat sdf = new simpledateformat("yyyy年mm月dd日 hh:mm:ss");
string s = sdf.format(d);
system.out.println(s);
使用此方法时,可以在创建该类对象时使用构造函数赋值,把我们需要的格式传入进去,当我们调用该方法时,将date类的对象传入进去时,就能将格式变更为我们需要的格式,并返回一个字符串类型。
string str = "2080-08-08 12:23:45";
simpledateformat sdf = new simpledateformat("yyyy-mm-dd hh:mm:ss");
date d = sdf.parse(str);
system.out.println(d);
使用此方法时,可以在创建该类对象时使用构造函数赋值,把我们需要的格式传入进去,当我们调用该方法时,将我们输入的与格式匹配的字符串传入,就会将我们输入的字符解析出来,返回一个date对象。
simpledateformat sdf = new simpledateformat();
sdf. applypattern("yyyy-mm-dd hh:mm:ss");
当创建该类对象时没有使用构造函数赋予默认格式,或程序后期需更改指定的格式时,可以通过此方法给这个对象赋予需要的时间格式。
1. arrays类是一个工具类,以此类举例分析工具类。
2. arrays类中有构造方法吗?我们为什么在帮助文档上没有看到arrays类的构造方法?
一个类如果没有构造方法,系统将提供一个无参的构造方法。而我们没有在帮助文档上看到arrays类的构造方法是因为这个类的构造方法被私有化了,外界是无法使用的,所以在帮助文档就看不到,通过源码我们找到了 private arrays() { }。
3. arrays类的这种设计是常用的工具类的设计思想:把构造方法私有;成员全部用static修饰。
4. 工具类中的成员属性一般设置为private final static(私有,不可修改,静态)类型。保证不能让外部修改成员属性。
5. 连接池对象应该是一个应用只创建一次就可以的,不需要每次使用都创建一个新的连接池。此时可以直接将连接池设置为静态成员常量,如果要使用可以设置方法返回该常量,这样一个应用就只有一个连接池。
集合是一个容器,用来存储和获取数据的,集合主要可以分为2大类:
单列集合(collection):
单列集合又可以分为list(元素可重复,有序)集合,和set(不可重复,无序)集合
双列集合(map):
双列集合的主要实现类为hashmap
list集合是一个接口,其中的元素特点是有序和可以重复。该接口继承自collection
list集合的2个具体实现类为:
arraylist集合:排序方式为数组排序,查找块,增删慢。
linkedlist集合:排序方式为链表排序,查找慢,增删慢。
list集合中的主要实现方法有:
void add(int index,e element):在指定位置添加元素
e remove(int index):删除指定位置的元素
e get(int index):获取指定位置的元素
e set(int index,e element):修改指定位置的元素
list集合中的三种遍历方式:
迭代器:可以使用iterator迭代和listiterator迭代
iterator迭代器中只有显示元素和移除元素的功能。
listiterator迭代器中还有增加元素等功能。
增强for:可以使用foreach遍历元素
普通for:因为list集合是有序的,故可以使用普通for遍历元素
并发修改异常:concurrentmodificationexception
当方法检测到对象的并发修改,但不允许这种修+改时,抛出此异常。
产生的原因:迭代器依赖于集合而存在,在判断成功后,集合中添加了新的元素,而迭
代器并不知道,所有就报错了。
解决方法:可以使用listiterator迭代器,在迭代过程中可以修改元素
可以使用普通for遍历,在遍历过程中可以对元素进行修改
set集合是一个接口,其中的元素特点是元素唯一,存储元素无序。该接口继承自collection
set集合只有一个具体实现类:hashset集合。
它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变
添加功能的执行过程中,是进行了数据的判断的。分别使用hashcode()和equals()判断
hashcode():对数据的hash值进行判断,如果hash不同,就直接将元素添加
equals():如果hash值相同,就对数据使用equals()方法进行判断,如果不同就添加
如果我们使用hashset集合存储对象,你要想保证元素的唯一性,就必须重写hashcode()和equals()方法。
hashset集合的遍历:
因为hashset集合是无序的,故只能使用迭代器和增强for进行遍历。
hashset集合中的成员方法:
因为hashset实现set接口,set又继承自collection,故一般使用collection中的方法
map集合是一个接口,其实现类为hashmap,使用特点如下:
将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
如:学生的学号和姓名(it001 林青霞)(it002 张曼玉)(it003 王祖贤)
hashmap集合中的主要成员方法:
v put(k key,v value):添加元素
v remove(object key):根据键删除键值对元素
void clear():移除所有的键值对元素
boolean containskey(object key):判断集合是否包含指定的键
boolean containsvalue(object value):判断集合是否包含指定的值
boolean isempty():判断集合是否为空
int size():返回集合中的键值对的对数
v get(object key):根据键获取值
set<k> keyset():获取所有键的集合
collection<v> values():获取所有值的集合
set< entryset<键 , 值>> entryset():获取hashmap集合中所有的键值对
hashmap集合的遍历:
使用keyset()方法获取所有键的集合,在通过迭代器或者增强for遍历集合
通过entryset()方法获取集合中所有的键值对,再通过迭代器或增强for遍历集合
hashmap集合的注意事项:
问题来源:使用该集合时,如果把对象作为键存入,当对象里的属性改变时,键所对应的hash值也会改变,这时使用get(object key)方法用来获取该键对应的值时会出错。
应对措施:1.如果将对象作为键使用时,使用put方法添加到集合中后,建议不要再修改该对象中的属性,因为修改后该键的hash值也会相应改变,会导致不能获取到值。2.在遍历hashmap集合时,建议使用entryset方法获取所有的键值对,再遍历。
file类的概述:
file是文件和目录路径名的抽象表示形式,也就是说文件和目录是可以通过file封装成对象的。
目录:其实就是文件夹
file类的构造方法:
file(string pathname):通过将给定路径名字符串转换为抽象路径名来创建一个新 file 实例。
file(string parent, string child):根据 parent 路径名字符串和 child 路径名字符串创建一个新 file 实例。
file(file parent, string child):根据parent 抽象路径名和 child 路径名字符串创建一个新 file 实例。
file类中的主要成员方法:
public boolean createnewfile():创建文件;文件不存在,创建文件返回true;文件存在,创建文件失败并返回false
public boolean mkdir():创建目录;如果目录不存在,创建目录并返回true;目录存在,创建目录失败并返回false
public boolean mkdirs():创建多级目录;一般情况下可以使用mkdirs()方法创建单级目录。
public boolean delete():删除文件和目录;
注意:如果一个目录中有内容(目录,文件),就不能直接删除。应该先删除目录中的内容,最后才能删除目录。
public boolean isdirectory():判断是否是目录
public boolean isfile():判断是否是文件
public boolean exists():判断是否存在
public string getabsolutepath():获取绝对路径
public string getpath():获取相对路径
public string getname():获取名称
public string[] list()返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。
相对路径和绝对路径;
绝对路径:是以盘符开始的路径。d:\\aa\\b.txt
相对路径:不以盘符开始。相对于当前的项目而言,在项目的目录下。如何显示出来呢?刷新项目就可以了。
字节流的概述:
字节流可以分为字节输入流和字节输出流。
字节输出流写数据:fileoutputstream
outputstream:这是抽象类,是表示输出字节流的所有类的超类
fileoutputstream:这是字节输出流的具体实现类,将数据写入 file
构造方法:fileoutputstream(string name):创建一个向具有指定名称的文件中写入数据的输出文件流。
fileoutputstream(file file, boolean append) :第二个参数是true即可实现数据的追加写入。
字节流写数据的步骤:
a:创建字节输出流对象
b:调用写数据的方法
c:释放资源
字节输出流中用到的主要成员方法:
public void write(int b):一次写一个字节
public void write(byte[] b):一次写一个字节数组
public void write(byte[] b,int off,int len):一次写一个字节数组的一部分
string类中一个方法:byte[] getbytes() 将字符串转换为字节数组
字节输入流读数据:fileinputstream
inputstream:这是抽象类,是表示输入字节流的所有类的超类
fileinputstream:这是字节输入流的具体实现类,将数据写入 file
构造方法:fileinputstream (string name):创建一个向具有指定名称的文件中写入数据的输入文件流。
字节流读数据的步骤:
a:创建字节输入流对象
b:调用读数据的方法
c:释放资源
字节输入流中用到的主要成员方法:
public int read(byte[] b):从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中
返回值是读入缓冲区的字节总数,也就是实际的读取个数如果因为已经到达文件末尾而没有更多的数据,则返回 -1。
read():从此输入流中读取单个字节。
当文件小于1g时,可以尝试如下方式:
fileinputstream fis = new fileinputstream(""); //创建读取流对象
fileoutputstream fos = new fileoutputstream(""); //创建写入流对象
//定义一个字节数组,可以装下整个读取的文件
byte[] arr = new byte[fis.available()]; // 文件有多大, 我的数据就有多大
fis.read(arr); //将文件读入arr字节数组中
fos.write(arr); //将arr字节数组中的内容写入到指定的位置
字节缓冲流概述:
字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流。字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。
字节缓冲输出流:bufferedoutputstream
需在创建该对象时传入fileoutputstream(字节输出流)对象,方法可以使用字节输出流中的方法。
字节缓冲输入流:bufferedinputstream
需在创建该对象时传入fileinputstream (字节输入流)对象,方法可以使用字节输入流中的方法。
转化流概述:转换流 = 字节流 + 编码表
字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
汉字存储的规则:左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,一般是负数。
编码表了解:
ascii : 美国标准信息交换码, 用一个字节的7位表示数据
iso-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ascii
gb2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ascii
utf-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, 兼容ascii,用在网页上可以统一页
面中的中文简体繁体和其他语言的显示.
如果出现乱码即为编码和解码时使用的码表不一样。在写代码时得保证编码和解码时码表一致。
编码:把看得懂的变成看不懂的。 解码:把看不懂的变成看得懂的。
转换流的构造方法:
outputstreamwriter 字符输出流
public outputstreamwriter(outputstream out):根据默认编码把字节流的数据转换为字符流
public outputstreamwriter(outputstream out,string charsetname):根据指定编码把字节流数据转换为字符流
inputstreamreader 字符输入流
public inputstreamreader(inputstream in):用默认的编码读数据
public inputstreamreader(inputstream in,string charsetname):用指定的编码读取数据
outputstreamwriter(字符输出流)写数据方法:
public void write(int c):写一个字符
public void write(char[] cbuf):写一个字符数组
public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
public void write(string str):写一个字符串
public void write(string str,int off,int len):写一个字符串的一部分
inputstreamreader(字符输入流)读数据方法:
public int read():一次读取一个字符
public int read(char[] cbuf):一次读取一个字符数组
字符流概述:
转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。一般情况是不要用转换流的。
字符流的构造方法:
filewriter 字符输出流,写文件
filewriter():需传入一个file对象,或者一个字符串的文件地址。
filewriter(file file, boolean append):第二个参数是true即可实现数据的追加写入。
filereader 字符输入流,读文件
filereader():需传入一个file对象,或者一个字符串的文件地址。
filewriter(字符输出流)写数据方法:
public void write(int c):写一个字符
public void write(char[] cbuf):写一个字符数组
public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
public void write(string str):写一个字符串
public void write(string str,int off,int len):写一个字符串的一部分
filereader(字符输入流)读数据方法:
public int read():一次读取一个字符
public int read(char[] cbuf):一次读取一个字符数组
bufferedwriter:字符缓冲输出流
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小,
或者接受默认的大小。在大多数情况下,默认值就足够大了。
构造方法:bufferedwriter(writer out):需传入一个字符输出流。
普通方法:字符缓冲输出流的普通方法和字符输出流中的普通方法一样运用。
特有方法:void newline():写入一个行分隔符,这个行分隔符是由系统决定的。当使用这个方法后请刷新flush()。
bufferedreader:字符缓冲输入流
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。 可以指定缓冲区的大小,或者
可使用默认的大小。大多数情况下,默认值就足够大了。
构造方法:bufferedreader(reader in):需传入一个字符输入流。
普通方法:字符缓冲输入流的普通方法和字符输入流中的普通方法一样运用。
特有方法:string readline():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null。
try(filereader fr = new filereader("src/1.txt"); filewriter fw = new filewriter("src/2.txt") ){ } catch (exception e) { // todo auto-generated catch block e.printstacktrace(); } |
当把io流的创建对象的过程写在try内部时,不用进行关流操作,会自动关流。
字节流------->万能流(但是不适合 读取文本)
fileoutputstream
bufferedoutputstream : fileoutputstream 的升级版
fileinputstream
bufferedinputstream : fileinputstream的升级版
字符流-----> 只适合读取文本
filewrite
bufferedwrite : filewrite的升级版
fileread
bufferedread : fileread的升级版
跨系统换行符 ------> newline()
一次读取一行数据---> readline()
bufferedreader br = new bufferedreader(new filereader("窗里窗外.txt"));
string line;
while((line=br.readline())!=null) {//这里的返回值是一个 null 不是 -1, 因为该方法的返回值是string,
system.out.println(line);
}
br.close();
create database 数据库名称 [character set 字符集 collate 字符集校对规则];
查看数据库服务器中所有的数据库:show databases;
查看某个数据库的定义信息: show create database 数据库名称;
alter database 数据库名称 character set 字符集 collate 校对规则;
drop database 数据库名称;
切换数据库:use 数据库名称;
查看当前正在使用的数据库:select database();
create table 表名称(字段名称 字段类型(长度) 约束,字段名称 字段类型(长度) 约束…);
查看某个数据库下的所有的表: show tables;
查看某个表的结构信息: desc 表名;
drop table 表名;
添加列: alter table 表名 add 列名 类型(长度) 约束;
修改列类型,长度和约束:alter table 表名 modify 列名 类型(长度) 约束;
删除列:alter table 表名 drop 列名;
修改列名称:alter table 表名 change 旧列名 新列名 类型(长度) 约束;
修改表名:rename table 表名 to 新的表名;
修改表的字符集:alter table 表名 character set 字符集;
向表中插入某些列:insert into 表名 (列名1,列名2,列名3…) values (值1,值2,值3…);
向表中插入所有列:insert into 表名 values (值1,值2,值3…);
update 表名 set 列名=值,列名=值 [where 条件];
delete from 表名 [where 条件];
重点,请查看下述mysql查询笔记。
外键约束的添加方式:constraint fk_score_sid(约束名) foreign key (sid) references student(id);
alter table score1 add constraint fk_stu_score foreign key(sid) references stu(id);
也可以直接在sqlyog中直接右击表,点击关联/外键按钮创建外键。
有2个表score和student,当在score中添加外键约束时,是以student为主表进行统计,此时student表中必须有主键约束,在score中添加student的主键为score的外键约束。
a) 事务的概念、实现方法和基本特性:
事务:指的是逻辑上的一组操作,组成这组操作的各个逻辑单元,要么全都成功,要么全都失败。
开启事务:start transaction; |
提交事务:commit; |
回滚事务:rollback; |
原子性:事务的不可分割,组成事务的各个逻辑单元不可分割。
一致性:事务执行的前后,数据完整性保持一致。
隔离性:事务执行不应该受到其他事务的干扰。
持久性:事务一旦结束,数据就持久化到数据库中。
b) 事务的隔离级别:
隔离性:一个事务的执行,不应该受到其他事务的干扰。如果不考虑隔离性(一个事务执行受到其他的事务的干扰),引发一些安全问题。 |
|
脏读:一个事务读到了另一个事务未提交的数据,导致查询结果不一致。 |
|
不可重复读:一个事务读到了另一个事务已经提交的update的数据,导致多次查询结果不一致。 |
|
虚读/幻读:一个事务读到了另一个事务已经提交的insert的数据,导致多次查询结果不一致。 |
|
read uncommitted: |
脏读,不可重复读,虚读都有可能发生 |
read committed: |
避免脏读。但是不可重复读和虚读是有可能发生 |
repeatable read: |
避免脏读和不可重复读,但是虚读有可能发生。 |
serializable: |
避免脏读,不可重复读,虚读。 |
1. 单表查询
a. 基础查询:
select * from stu;
select sid, sname, age from stu;
b. 条件查询:在where语句中使用如下关键字=、!=、<>、<、<=、>、>=;between…and; in(set);is null; is not null;and;or;not;
查询姓名不为null的学生记录:select * from stu where sname is not null;
查询性别非男的学生记录:select * from stu where gender!='male';
查询学号不是s_1001,s_1002,s_1003的记录:
select * from tab_student where s_number not in ('s_1001','s_1002','s_1003');
c. 模糊查询:在where语句中使用关键字like,并使用通配符 _(一个字符)或者%(0-n个字符)。(下划线或百分号)
查询姓名由5个字母构成的学生记录:select * from stu where sname like '_____';
查询姓名中第2个字母为“i”的学生记录:select * from stu where sname like '_i%';
d. 字段控制查询:
e. 排序: order by 列名 asc(默认) desc
查询所有学生记录,按年龄升序排序:select * from stu order by sage asc;
查询所有学生记录,按年龄降序排序:select * from stu order by age desc;
查询所有雇员,按月薪降序排序,如果月薪相同时,按编号升序排序:
select * from emp order by sal desc,empno asc;
f. 聚合函数 sum avg max min count
查询emp表中记录数:select count(*) as cnt from emp;
查询emp表中有佣金的人数:select count(comm) cnt from emp; count只统计不为null的列数。
查询所有雇员月薪和:select sum(sal) from emp;
查询所有雇员月薪+佣金和:select sum(sal+ifnull(comm,0)) from emp;
统计所有员工平均工资:select avg(sal) from emp;
查询最高工资和最低工资:select max(sal), min(sal) from emp;
g. 分组查询 需使用group by子句,注:凡和聚合函数同时出现的列名,一定要写在group by 之后
查询每个部门的部门编号和每个部门的工资和:select deptno, sum(sal) from emp group by deptno;
查询每个部门的部门编号以及每个部门的人数:select deptno,count(*) from emp group by deptno;
查询工资总和大于9000的部门编号以及工资和:
select deptno, sum(sal) from emp group by deptno having sum(sal) > 9000;
h. having与where的区别:
having是在分组后对数据进行过滤,where是在分组前对数据进行过滤。
having后面可以使用聚合函数(统计函数), where后面不可以使用聚合函数。
where是对分组前数据的约束;而having是对分组后数据的约束。
i. 查询中各关键词的使用顺序:
from -> where -> group by -> having -> select -> order by
2. 多表查询
作用:合并结果集就是把两个select语句的查询结果合并到一起!
合并结果集有两种方式:
union:去除重复记录,例如:select * from t1 union select * from t2;
union all:不去除重复记录,例如:select * from t1 union all select * from t2。
连接查询就是求出多个表的乘积,例如t1连接t2,那么查询出的结果就是t1*t2。内连接,等都属于连接查询。
重点语法:select * from emp,dept where emp.deptno=dept.deptno; 使用使用主外键来去除无用信息。
语法:select * from emp e inner join dept d on e.deptno=d.deptno;
内连接的特点:查询结果必须满足条件。
左外连接 left [outer] join
select * from emp e left outer join dept d on e.deptno=d.deptno;
左连接是先查询出左表,然后查询右表,右表中满足条件的显示出来,不满足条件的显示null。
右外连接 right [outer] join
select * from emp e right outer join dept d on e.deptno=d.deptno;
右连接就是先把右表中所有记录都查询出来,然后左表满足条件的显示,不满足显示null。
大家也都知道,连接查询会产生无用笛卡尔积,我们通常使用主外键关系等式来去除它。而自然连接无需你去给出主外键等式,它会自动找到这一等式:两张连接的表中名称和类型完全一致的列作为条件,例如emp和dept表都存在deptno列,并且类型一致,所以会被自然连接找到!
select * from emp natural join dept;
select * from emp natural left join dept;
求7369员工编号、姓名、经理编号和经理姓名
select e1.empno , e1.ename,e2.mgr,e2.ename from emp e1, emp e2 where e1.mgr = e2.empno and e1.empno = 7369;
1. jdbc概述
jdbc是一种用于执行sql语句的java api,可以为多种关系型数据库提供统一访问。没有jdbc的时候,如果现在要开发一套系统,使用java连接mysql数据库,那么这时候java程序员需要了解mysql驱动api,如果使用java连接oracle数据库,那么这个时候java程序员需要了解oracle数据库驱动api。sun公司提供一套统一的规范(接口)。然后各个数据库生产商提供这套接口的实现。这套接口规范就是jdbc的规范。
2. jdbc使用入门
jdbc的使用主要分为如下4步:
l 第一步:加载驱动 class.forname("com.mysql.jdbc.driver");
l 第二步:获得连接 connection conn = drivermanager.getconnection("url", "用户名", "密码");
l 第三步:基本操作 先使用连接对象获取执行sql语句的对象,在进行sql语句操作
l 第四步:释放资源 关流,连接流,操作sql语句对象的流,字符集流
3. 抽取jdbc工具类
因为传统jdbc的开发,注册驱动,获得连接,释放资源这些代码都是重复编写的。所以可以将重复的代码提取到一个类中来完成。
4. 配置文件详解
l 配置文件命名规范:文件名.properties; 内容:key=value;
l 使用方法
properties properties = new properties(); //创建配置文件对象
properties.load(new fileinputstream("url")); //将配置文件的详细地址使用文件读取流存入
object value = properties.getproperty("key"); //根据key取出对应的value值
5. jdbc的sql注入漏洞
l sql注入漏洞原因:
l 解决方法:
需要采用preparedstatement对象解决sql注入漏洞。这个对象将sql预先进行编译,使用?作为占位符。?所代表内容是sql所固定。再次传入变量(包含sql的关键字)。这个时候也不会识别这些关键字。
string sql = "select * from user where username = ? and password = ?"; // 编写sql语句
pstmt = conn.preparestatement(sql); // 预编译sql
pstmt.setstring(1, username); // 设置参数1,第一个?处
pstmt.setstring(2, password); // 设置参数2,第二个?处
rs = pstmt.executequery(); &nb
如对本文有疑问, 点击进行留言回复!!
MySQL-关系代数-并、交、差、等值连接、自然连接、左连接。。。
【MySQL牛客】10.获取所有非manager的员工emp_no
网友评论