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()完成更新
使用结果集更新数据
prepareStatement(String sql,int ResultSet.TYPE_SCROLL_SENSITIVE, int ResultSet.CONCUR_UPDATABLE)
在修改数据的时候要把指针指向要修改的行,所以用查询的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()方法实例化
ResultSetMetaData
| getColumnCount() | 返回查询结果中的列数 |
|---|---|
| isAutoIncrement(int 列号) | 判断指定列是否是自动编号 |
| getColumnName(int 列号) | 返回列的名称 |
var statement=conn.prepareStatement("select * from jb");
ResultSetMetaData rsmd=statement.getMetaData();
实例化方法



