JDBC(java数据库连接)提供了一套数据库操作标准,这些标准需要各个数据库厂商去实现并提供一个驱动程序,目前常见的4类JDBC驱动程序:
JDBC-ODBC |
直接利用微软的ODBC进行数据库连接操作,性能低,一般不推荐 |
JDBC本地驱动 |
直接使用各个数据库厂商提供的驱动程序,只能在特定的数据库上,性能高,可移植性低 |
JDBC网络驱动 |
JDBC转换为与DBMS无关的网络协议,又被某个服务器转化为一种DBMS协议,这样可以连接到多个数据库,所用的具体协议取决于提供者,通常是最灵活的 |
本地协议纯JDBC |
将JDBC调用直接转换为DBMS所使用的网络协议,这将允许用户从客户端直接调用DBMS服务器,是internet访问的一个实用的解决方法 |
数据类型 |
字节数 |
|
TINYINT |
1 |
|
SMALLINT |
2 |
|
MEDIUMINT |
3 |
|
INT0 |
4 |
|
BIGINT |
8 |
|
FLOAT |
4 |
|
DOUBLE |
8 |
|
DECIMAL(M,D) |
M+2 |
这里的M为数据的长度,D为小数点的位数 |
插入值 |
CHAR(3) |
存储需求 |
VARCHAR(3) |
存储需求 |
‘’ |
‘’ |
3个字节 |
‘’ |
1个字节 |
‘a’ |
‘a’ |
3个字节 |
‘a’ |
2个字节 |
‘ab’ |
‘ab’ |
3个字节 |
‘ab’ |
3个字节 |
‘abc’ |
‘ab’ |
3个字节 |
‘abc’ |
4个字节 |
‘abcd’ |
‘ab’ |
3个字节 |
‘abc’ |
4个字节 |
在MySQL中常用CHAR 和 VARCHAR 表示字符串。VARCHAR是可变长度的字符串。 当数据为CHAR(M)类型时,不管插入值的长度是实际是多少它所占用的存储空间都是M个字节;而VARCHAR(M)所对应的数据所占用的字节数为实际长度加1
文本类型用于表示大文本数据,例如,文章内容、评论、详情等:
TINYTEXT |
1个字节*字节 |
TEXT |
2个字节*字节 |
MEDIUMTEXT |
3个字节*字节 |
LONGTEXT |
4个字节*字节 |
时间与日期
数据类型 |
字节数 |
取值范围 |
日期格式 |
零值 |
YEAR |
1 |
1901~2155 |
YYYY |
0000 |
DATE |
4 |
1000-01-01~9999-12-31 |
YYYY-MM-DD |
0000-00-00 |
TIME |
3 |
-838:59:59~ 838:59:59 |
HH:MM:SS |
00:00:00 |
DATETIME |
8 |
1000-01-01 00:00:00~9999-12-31 23:59:59 |
YYYY-MM-DD HH:MM:SS |
0000-00-00 00:00:00 |
TIMESTAMP |
4 |
1970-01-01 00:00:01~2038-01-19 03:14:07 |
YYYY-MM-DD HH:MM:SS |
0000-00-00 00:00:00 |
YEAR类型用于表示年份,在MySQL中,可以使用以下格式指定YEAR类型 的值。
- 使用4位字符串或数字表示 2019或 ‘2019’ 都表示2019年,范围为1901—2155年
- 使用两位字符串表示 范围 ‘00’-‘99’ ,‘00’—'69’范围的值会被转换为 2000—2069范围的YEAR值,‘70’—'99’范围的值会被转换为1970—1999范围的YEAR 值。如果使用数字指定类似字符串指定,区别不能使用数子 00,00代表YEAR值是0000
TIME类型用于表示时间值可以使用以下格式指定TIME类型 的值
- 以’D HH:MM:SS’字符串格式表示。其中,D表示日可取0—34之间的值, 插人数据时,小时的值等于(DX24+HH)。例如,输入’2 11:30:50’插人数据库中的日期为59:30:50。
- 以’HHMMSS’字符串格式或者HHMMSS数字格式表示。 例如,输人’115454’或115454,插入数据库中的日期为11:54:54
- 使用CURRENT_TIME或NOW()输人当前系统时间。
DATETIME类型用于表示日期和时间值**可以使用以下格式指定
- 以’YY-MM-DD HH:MM:SS’或者’YYMMDDHHMMSS’字符串或数字格式表示的日期和时间
- 使用NOW来输人当前系统的日期和时间。
TIMESTAMP与DATETIME相同但取值范围比DATETIME小。这是3种不同的形式
- 使用CURRENT_TIMESTAMP输人系统当前日期和时间。
- 输人NULL时系统会输人系统当前日期和时间。
- 无任何输人时系统会输入系统当前日期和时间。
BLOB存储二进制类型的数据,例如:图片、PDF文档等。BLOB类型分为如下四种:
二进制类型 |
大小 |
TINYBLOB |
1个字节*字节 |
BLOB |
2个字节*字节 |
MEDIUMBLOB |
3个字节*字节 |
LONGBLOB |
4个字节*字节 |
数据库的基本操作
DDL |
数据定义语言 |
DML |
数据操作语言 |
DQL |
数据查询语言 |
DCL |
数据控制语言 |
mysql -u 用户名 -p 连接数据库 (我的用户名czdsb,密码123456) net start 服务器名字 :开启服务器 (我的服务器名字mysql80) net stop 服务器名字:关闭服务器
单行注释--或# 多行
这是DDL的指令,这里的[]都表示可选,输入时不用吧 [] 输进去,直接忽略就行
show databases |
查询全部数据库 |
SELECT DATABASE() |
查询当前数据库 |
CREATE [IF NOT EXISTS]数据库名[DEFAULT CHARSET 字符编码格式如UTF-8m4][COLLATE 排序规则] |
创建数据库 |
DROP DATABASE [IF NOT EXISTS]数据库名 |
删除数据库 |
use 数据库名 |
切换数据库 |
show tables |
查询当前数据库的表 |
desc 表名 |
查看表格内容 |
show create table 表格名 |
查看指定表的建表语句 |
create table 表名(
id int comment '注释',
变量名 变量类型
);
注意:在 )前面不能有,字符类形为varchar(容量大小)
alter database 数据库名 character set gbk; |
将数据库的字符集修改为gbk |
alter table 表名 rename to 表名; |
修改表名 |
alter table 表名 change name1 name2 变量类型; |
将字段name1变为name2 |
alter table 表名 modify 字段名 字段类型; |
修改字段数据类型 |
alter table 表名 add 字段名 字段类型; |
增加字段 |
alter table 表名 drop 字段名; |
删除字段 |
drop table 表名; |
删除数据表 |
插入数据
INSERT INTO 表名 [(字段名1,字段名2,...)]VALUES (值 1,值 2,…),(值 1,值 2,…); |
插入一条 |
INSERT INTO 表名 [(字段名1,字段名2,...)]VALUES (值 1,值 2,…),(值 1,值 2,…),...; |
插入多条内容 |
select * from 表名 查询表里的内容
UPDATE基本语法
UPDATE 表名 SET 字段名1=值1[,字段名2 =值2,…] [WHERE 条件表达式]; |
更新部分数据 |
update 表名 set 字段=值; |
将所有该字段的值都一起设定 |
update student set age=20,gender='female' where name='tom';
//将name为tom的记录 的age设置为20并将其gender设置为female
DELETE删除数据
DELETE FROM 表名 [WHERE 条件表达式];
如果加where条件筛选就只删一部分,不加就删完
查询
select * from 表名; |
查询所有字段 |
select 字段 或 常量 from 表名; |
查询指定字段,如select id,name from student;只查询名字和id |
select distinct 字段 from 表名; |
从查询结果中过滤重复数据,如select distinct gender from student; 结果为 男和女。DISTINCT关键字只能用在第一个所查列名之前 |
在SELECT查询语句中还可以使用加减乘除运算符。
select sname,age+10 from student; 即查询10年后的age(输出为原先age+10)
在java中加载驱动程序
String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
String DB_URL = "jdbc:mysql://localhost:3306/你的mysql数据库名字?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
String user="你的mysql的用户名",pass="你的mysql的密码";
Class.forName(JDBC_DRIVER);
Connection conn = DriverManager.getConnection(DB_URL,user,pass);
在这里用到了Connection与Statement接口
Connection方法 |
作用 |
createStatement() |
创建Statement对象 |
prepareStatement(String sql) |
创建prepareStatement对象 |
|
|
Statement方法 |
作用 |
executeUpdate(String sql) |
执行更新的操作,如insert,update,delete |
executeQuery(String sql) |
执行查询操作,返回一个结果 ResultSet 对象 |
addBatch(String sql) |
增加一个待执行的sql语句 |
executeBatch(String sql) |
批量执行sql语句 |
close() |
关闭Statement |
execute(String sql) |
执行sql语句 |
ResultSet接口 |
作用 |
next() |
将指针移向下一行 |
getInt(int index) |
按列的index取得指定列的整数 |
getInt(String name) |
按列的名字取得列的整数 |
getFloat(int index)与getFloat(String name) |
同上 |
getString(int index)getString(String name) |
同上 |
getDate(int index)getDate(String name) |
同上 |
ResultSet是一个set集合,本质是指针来存储,要用next()来把指针移向下一个
getString()可以接受任意类型的内容
查询时尽量不要用select * from user 来查询 ,尽量要指定查询哪一列
PreparedStatement
因为Statement接口安全性较差,所以一般用PreparedStatement接口,且PreparedStatement已预编译,执行效率高,以下是比Statement多的方法,使用Connection的prepareStatement(String sql)来实例化
executeUpadte() |
执行预编译的sql语句 |
executeQuery() |
查询,返回ResultSet对象 |
setFloat(int 列号,float值) |
设置值 |
setInt方法 |
同上 |
setString方法 |
同上 |
setDate方法 |
同上 |
PreparedStatement可以通过拼凑sql语句如:
String str="insert into jb (id,name,url) value(?,?,?)";
PreparedStatement statement=conn.prepareStatement(str);
实例化对象时传入一个 可拼凑的sql语句,用 ? 来当一个占位符
statement.setString(2, "沙立浩为什么这么骚");
这里就指定 将第 2个?替换为 "沙立浩为什么这么骚" 这个字符串
将全部的?替换后就可以 用executeUpadte()来执行你的sql语句了
在查询的时候将字符串 两端左右加 %,作为模糊查询
ALTER DATABASE 数据库 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin |
将指定数据库字符编码设置为utf-8 |
ALTER TABLE 表名 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin |
将指定表字符编码设置为utf-8 |
ALTER TABLE 表名 CHANGE 字段名 字段名 VARCHAR( 45 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL |
将指定字段字符编码设置为utf-8 |
有时候向数据库里输入时会产生 字符编码不一致而报错的情况,所以要设置一下
处理大数据
使用CLOB和BLOB两种类型的字段,在CLOB中存储海量文件 。
mysql中提供了longtext等文本类型来存储大文本数据。
在使用PreparedStatement来对 text 类型输入时,可以这样:
statement.setAsciiStream(3, new FileInputStream(f), (int)f.length());
调用setAsciiStream(int index, input对象, int 文件大小);方法将 文件流中的文本输出到数据库中。
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jk?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC","root","123456");
System.out.print("已连接");
PreparedStatement statement=conn.prepareStatement("select n from note where id like 2");
ResultSet rSet=statement.executeQuery();
rSet.next();
Scanner s=new Scanner(rSet.getAsciiStream(1));
while (s.hasNext())
{
System.out.println(s.next());
}
这里是先用rSet中 的next()把指针移向我们要读的数据
然后 rSet.getAsciiStream(1) 得到 要读的数据的 输入流,然后交给Scanner来处理文本
CallableStatement接口
该接口主要调用数据库中的储存过程,可以接收过程的返回值
那么mysql的储存过程又是啥呢?
set @a=10; --这相当于定义了叫 a 的一个值为10 的用户变量
select @a; --将这个用户变量输出 --用户变量一定要在前面加 @
create procedure 过程名 (各种参数....)
储存过程有三种类型声明
- IN 只会读进来,在过程里操作该变量,在过程结束后也不会影响变量
- INOUT 把值传进来,在过程中的修改会被保留
- OUT 过程中对此值的操作会被保留
注意:在建立 储存过程之前 要修改分隔符 (即 delimiter 分隔符 指令)
getInt(int 编号),getFloat(int 编号) |
根据编号来取出返回值 |
setInt(int 编号)setFloat(int 编号) |
设置指定编号的内容 |
registerParameter(int 编号,int Types.类型) |
设置返回值的类型 |
Call 通过Connection类的prepareCall()方法来实列化
主要就是处理 sql的存储过程
可以滚动的结果集
在之前讲的ResultSet中只能从前往后输出,那要输出可以滚动的结果集,可以这样:
prepareStatement(String sql,int ResultSet.TYPE_SCROLL_SENSITIVE,
int ResultSet.CONCUR_READ_ONLY)
//通过这个方法来得到一个 可滚动的PrepareStatement对象
其中ResultSet.TYPE_SCROLL_SENSITIVE与ResultSet.CONCUR_READ_ONLY都是
ResultSet中的int常量。
ResultSet中的常量 |
描述 |
TYPE_FORWARD_ONLY |
表示指针只能向后滚动(默认值) |
TYPE_SCROLL_SENSITIVE |
表示指针可以滚动,可以更新内容 |
TYPE_SCROLL_INSENSITIVE |
表示指针可以滚动,不可以更新内容 |
CONCUR_READ_ONLY |
用只读的方式打开数据库 |
CONCUR_UPDATABLE |
表示ResultSet可以更新 |
ResultSet中的方法补充 |
描述 |
absolute(int index) |
将结果集移向指定行 |
previous() |
将结果向前移动 |
afterLast() |
将结果集移到末尾之后 |
beforeFirst() |
将结果集移到首行之前 |
first() |
将结果集移到第一行 |
last() |
将结果集移到最后一行 |
updateString(int 列号,String x) |
更新指定列的内容,改方法被重载多次 |
updateString(String 列名,String x) |
更新指定列的内容,改方法被重载多次 |
moveToInsertRow() |
将指针移到 插入行 |
cancelRow() |
取消更新数据,在updateRow()调用之前有效 |
insertRow() |
插入行数据 |
deleteRow() |
删除行数据 |
使用结果集插入数据
- 在创建PrepareStatement对象是必须指定结果集可以更新数据
-
prepareStatement(String sql,int ResultSet.TYPE_SCROLL_SENSITIVE,
int ResultSet.CONCUR_UPDATABLE)
- 设置可更新后,调用ResultSet的moveToInsertRow()将指针移向可插入的列
- 调用ResultSet 的Update***()之类的方法
- 最后使用insertRow()完成更新
使用结果集更新数据
在修改数据的时候要把指针指向要修改的行,所以用查询的sql语句
再用last(),再调用ResultSet 的Update***()之类的方法
最后调用updateRow()来完成修改
注意:在执行updateRow()方法之前,如果发现更新的数据有错误,可以使用
使用结果集删除数据
执行 ResultSet 的deleteRow()删除一行
批处理
使用批处理可以一次性插入多条sql语句,
PreparedStatement statement=conn.prepareStatement("insert into jb(id,name,countriy,day) values(?,?,?,?)");
for(int i=3;i<6;i++)
{
statement.setString(1, i+"");
statement.setString(2,"沙立浩被干的次数"+i);
statement.setString(3,"保加利亚"+i);
statement.setDate(4, new Date(new java.util.Date().getTime()));
statement.addBatch();
}
statement.executeBatch();
使用PreparedStatement对象的addBatch()加入批处理等待,
最后用executeBatch()执行批处理
事务处理
所谓的十五就是所有操作要么一起成功,要么都失败,事务本身具有原子性,一致性,隔离性(独立性),持久性
mysql对事物的支持 |
描述 |
set autocommit=0 |
取消自动提交,开启事务处理 |
set autocommit=1 |
开启自动提交,关闭事务处理 |
start transaction |
启动事务 |
begin |
启动事务,相当于start transaction |
commit |
提交事务 |
rollback |
回滚 |
savepoint 事务保存点的名称 |
设置回滚点 |
rollback to savepoint 保存点名称 |
回滚到指定保存点 |
应用事件处理:
- 设置set autocommit=0
- 开启事务start transaction或begin
- 编写更新语句之类的
- 提交事务commit
在java中怎么实现这些步骤呢?
- 取消Connection中设置的自动提交方式 setAutoCommit(false)
- 如果批处理的时候操作成功就可以 Connection对象.commit()提交事务
- 有异常可以回滚** Connection对象.rollback()**,可以指定要回滚的保存点
- 可以设置savepoint,"SavePoint 检查点名字=Connection对象.setSavePoint()"
使用元数据分析数据库
DatabaseMetaData类可由Connection的getMetaDta()方法实例化
getDatabaseProductName() |
得到数据库的名称 |
getDriverMajorVersion() |
得到数据库的主版本号 |
getDriverMinorVersion() |
得到数据库的次版本号 |
getPrimaryKeys(String,String,String) |
得到表主键信息,1.表类别,2.表模式3.表名称4.列名称5.主键中的序列号,6.主键的名称。返回ResultSet对象 |
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jk?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC","root","123456");
System.out.print("已连接");
DatabaseMetaData dm=conn.getMetaData();//通过getMetaData()方法实例化
getColumnCount() |
返回查询结果中的列数 |
isAutoIncrement(int 列号) |
判断指定列是否是自动编号 |
getColumnName(int 列号) |
返回列的名称 |
var statement=conn.prepareStatement("select * from jb");
ResultSetMetaData rsmd=statement.getMetaData();
实例化方法