JDBC-day01
JDBC基本概念
- 概念: Java DataBase Connectivity 即Java数据库连接, 用java语言操作数据库.
- JDBC本质: 我们期望使用统一的一套java代码可以操作所有的数据库,为此,sun公司就定义了医药操作所有关系型数据库的规则(也就是接口),而其每个数据库对这个接口的实现类由该数据库公司自己实现.所以, 我们可以说JDBC的本质就是:官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口.同时各个数据库厂商自己去实现这个接口,提供数据库驱动的jar包.从而我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类
JDBC快速入门
- 步骤:
- 导入对应数据库的驱动jar包,要用mysql就导入mysql的.
- 复制jar包,到项目下(可以新建一个目录libs,jar包都放在该目录下).
- 将libs目录–>右键–>添加为库.
- 注册驱动,让程序知道是用哪个数据库.
Class.forName("com.mysql.jdbc.Driver");
.
- 获取数据库连接对象Connection.
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/cart", "root", "root");
.
- 定义sql语句.
String sql = "update product set name = '话说' where id = 1";
.
- 获取执行sql语句的对象 Statement.
Statement state = conn.createStatement();
.
- 执行sql语句,接收返回的结果.
int count = state.executeUpdate(sql);
.
- 处理结果.
- 释放资源.
- 导入对应数据库的驱动jar包,要用mysql就导入mysql的.
对JDBC中各个接口和类详解
-
详解各个对象
- DriverManager(类): 驱动管理对象.
- 功能
-
注册驱动,告诉我们的程序该使用哪个数据库的jar包.
-
使用的方法:
public static void registerDriver(Driver driver) throws SQLException
. -
写代码使用该方法:
Class.forName("com.mysql.jdbc.Driver")
,通过查看Driver的源码,我们发现,在Driver类中存在静态代码块static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException(“Can’t register driver!”);
}
} -
注意:在导入mysql5的jar包以后,我们注册驱动的语句可以不用写,因为在jar包下的
META-INF
文件夹中的services
中帮我们写了,不过我们还是建议写上,我们不知道驱动咋写的时候也可以去META-INF
文件夹中的services
中复制.
-
-
获取数据库连接.
- 使用的方法:
public static Connection getConnection(String url, String user, String password)
. - 参数:
- url:指定连接的路径
- 语法: jdbc:mysql://ip地址(或者域名,用于找到计算机):端口号(用于找到mysql软件)/数据库名称
- 例子:jdbc:mysql://localhost:3306/cart
- 细节:如果连接的是本机的mysql服务器,并且mysql的默认端口是3306,则url中的
ip和端口
可以省略,所以url可以简写为:jdbc:mysql:///数据库名称
- user:用户名
- password:密码
- url:指定连接的路径
- 使用的方法:
-
- 功能
- Connection(接口): 数据库连接对象
- 功能:
- 获取执行sql语句的对象
- 方法1:
Statement createStatement()
. - 方法2:
PreparedStatement prepareStatement(String sql)
.
- 方法1:
- 管理事务:
- 开启事务:
void setAutoCommit(boolean autoCommit)
,调用该方法设置参数为false
则开启事务. - 提交事务:
void commit()
. - 回滚事务:
void rollback()
.
- 开启事务:
- 获取执行sql语句的对象
- 功能:
- Statement(接口,重要): 执行静态sql语句对象
- 方法1(了解):
boolean execute(String sql)
,返回true表示执行的是DQL语句,返回false表示执行的是 DML语句. - 方法2:
int executeUpdate(String sql)
,执行DML语句(数据操作语言,增删改,insert,update,delete)
,DDL语句(数据定义语言,创建/删除表和库,create,alter,drop)
.- 返回值: 表示影响的行数(针对DML语句,而对DDL永远返回0,因为它不返回任何内容).
- 返回值作用: 可以通过影响的行数来判断DML语句是否执行成功,返回值>0则执行成功,反之则执行失败.
- 方法3:
ResultSet executeQuery(String sql)
,执行DQL语句(数据查询语言查询语句,select). - 练习,针对product表:
- 添加一条记录:
String sql = "insert into product(id,name,price) value(null , '平板2' , 500)",其中
product(id,name,price)中的括号里的参数表示增加哪一个字段内容,不写就表示增加所有字段
.- 注意:这里
value
可以写成values
,在插入一条数据时,用values
较快,插入多行数据时,用value
较快.
- 注意:这里
- 删除一条记录:
String sql = "delete from product where id = 2";
. - 修改一条记录:
String sql = "update product set name = '平板' where id = 1";
. - 创建一张表:
String sql = "create table student (id int, name varchar(20))";
. - 删除一张表:
String sql = "drop table student";
.
- 添加一条记录:
- 方法1(了解):
- ResultSet(接口): 结果集对象,封装查询结果.
- next(): 游标向下移动一行(默认光标指向位置是表头,此时是没有数据的,向下移动一行后就有数据了),同时可以通过该方法判断是否到达最后一行末尾(即是否有数据),如果有数据,则返回true,反之则返回false.
- getXxx(参数): 获取数据.
- Xxx代表
数据类型
,因为它是一次获取一行当中某一列的值,不是一次获取一整行的,例如: int getInt(). - 参数有两种情况:
- int类型: 代表列的编号,从
1
开始,不是从0开始,如:getInt(1). - String类型: 代表列的名称,如:getString(“id”).
- int类型: 代表列的编号,从
- Xxx代表
- 注意:
- ResultSet的使用步骤:
- 游标向下移动一行.
- 判断是否有数据.
- 获取数据.
- ResultSet的使用步骤:
- DriverManager(类): 驱动管理对象.
while (rs.next()) {
int id = rs.getInt(1);
String name = rs.getString("name");
double price = rs.getDouble("price");
String data = "id = " + id + "name = " + name + "price = " + price;
System.out.println(data);
}
* 练习:
* 定义一个方法,查询`db_student`数据库中`studentinfo`中的数据,并将其封装为对象,然后打印.
* 思路:表其实和类的定义很类似,定义字段名,字段类型等,而表中每一行数据和一个对象类似,有表中每个字段的内容,所以我们可以把表映射成一个类,把查询的每一行数据封装成该类对象,然后用集合将所有对象都装载在一起返回.
1. 定义一个`Studentinfo`类,封装数据库中表的各个字段.
2. 定义方法 public List<Studentinfo> finaAll(),实现对数据库中所有数据的查询并将数据添加到list集合中.
3. 调用方法.
* PreparedStatement(statement的子接口): 执行动态sql语句
1. **SQL注入问题**: 在拼接sql语句时,有一些sql的特殊关键字参与字符串的拼接,会造成一些安全性问题
* 例如: `select * from usertable where username = 'abc' and password = 'a' or 'a' = 'a'`,前面的账号密码是错的,但是这个sql语句是恒成立的,因为后面有个`or 'a' = 'a'`,这就会把数据库中所有数据都查出来,同时导致程序出问题.
2. 解决sql注入问题: 使用PreparedStatement对象来解决.
3. 预编译sql语句:参数使用`?`作为占位符,在执行的时候,给`?`赋值就行了,这个虽然步骤麻烦一点,但是安全一些.
4. 使用步骤:
1. 导入对应数据库的驱动jar包,要用mysql就导入mysql的.即复制jar包,到项目下(可以新建一个目录libs,jar包都放在该目录下).
2. 将libs目录-->右键-->添加为库.
3. 注册驱动,让程序知道是用哪个数据库.
* `Class.forName("com.mysql.jdbc.Driver");`.
4. 获取数据库连接对象Connection.
* `Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/cart", "root", "root");`.
5. 定义sql语句.
* **注意**: sql的参数使用`?`作为占位符.如`String sql = "update product set name = ? where id = ?";`.
6. 获取执行sql语句的对象 PreparedStatement: 方法为`PreparedStatement prepareStatement(String sql)`.
* `PreparedStatement ps = conn.prepareStatement(sql);`.
7. 给`?`赋值
* 用到PreparedStatement中的setXxx(参数1, 参数2)方法.
* 其中,**参数1**表示?的位置编号,从1开始,**参数2**表示?的值.
7. 执行sql语句,接收返回的结果,在这里就不需要传递sql语句了,因为在步骤6中已经传递过了.
8. 处理结果.
9. 释放资源.
5. 改造登录例子代码:***[PrepareStatement改进登录代码](https://github.com/fanfan999/WebCodes/blob/master/JdbcDemo/fan/LoginUser_PrepareStatement.java)***
6. 注意:我们以后使用PrepareStatement来完成增删查改的所有操作
1. 可以防止SQL注入.
2. 效率比Statement高.
抽取JDBC工具类: JDBCUtils类
- 目的: 简化书写
- 分析:
- 抽取注册驱动.
- 抽取一个方法,获取连接对象.
- 需求: 不想传递参数(url,user,password等),因为太麻烦,但是 又想保证工具类的通用性,即不同url,user等也可以运行.
- 解决办法: 使用配置文件:
- jdbc.properties
- url =
- user =
- password =
- jdbc.properties
- 抽取释放资源.
- 代码:***JDBC工具类及测试代码***
- 练习:
- 需求: 通过键盘录入用户名和密码判断用户是否登录成功,给出提示.
- 步骤
- 创建数据库表,包括用户名和密码两个字段.
- 创建一个类
LoginUser.java
测试.
- 代码:***用户登录测试类***
需要注意的点:
- JAVA中两个
基1
的点:- 在查询语句
ResultSet
中,参数是从1
开始的. - 在预编译接口
PreparedStatement
对象中,参数也是从1
开始的.
- 在查询语句
- 上面提到的对象中,只有
DriverManager
是类,其它的都是接口.