一、数据库驱动
链接数据库和应用程序的中间环节,不同的数据库会有不同的驱动,所以对于java开发者需要一个规范来统一操作数据库,这就出现了JDBC
二、JDBC
JDBC一个java数据库的规范,对于java人员只需要掌握JDBC就可以了,没有什么问题是加一层解决不了的。我们需要java.sql和javax.sql,还需要导入一个数据库驱动包mysql-connector-java
三、第一个JDBC程序
创建测试数据库
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy;
CREATE TABLE `users`(
id INT PRIMARY KEY,
NAME VARCHAR(40),
PASSWORD VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(1,'zhansan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')
1、创建一个普通项目
2、导入数据库驱动
3、编写测试代码
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//2.用户信息和url
//useUnicode=true&characterEncoding=utf8&useSSL=true
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username="root";
String password="123456";
//3.链接成功,数据库对象,connection代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//4.执行SQL的对象,去执行SQL,statement的对象
Statement statement = connection.createStatement();
String sql="SELECT * FROM users";
ResultSet resultSet = statement.executeQuery(sql);//返回结果,封装了所有我们全部查询出的结果
while(resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));
System.out.println("name="+resultSet.getObject("NAME"));
System.out.println("pwd="+resultSet.getObject("PASSWORD"));
System.out.println("email="+resultSet.getObject("EMAIL"));
System.out.println("birth="+resultSet.getObject("birthday"));
System.out.println("=======================================");
}
//5.释放链接
resultSet.close();
statement.close();
connection.close();
}
}
步骤总结:
(1)加载驱动
(2)连接数据库 DriverManager
(3)获得执行sql对象 Statement
(4)获得返回的结果集
(5)释放连接
DiverManager
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
URL
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
//jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3
//oracle -- 1521
//jdbc:oracle:thin:@localhost:1521:sid
Statement 执行SQL对象 PrepareStatement 执行SQL对象
statement.executeQuery();//查询返回结果 ResultSet
statement.executeUpdate();//更新,插入,删除都是这个,返回一个受影响的行数
statement.execute();//执行任何SQL
ResultSet查询结果集:封装所有查询结果
获得指定的数据类型
ResultSet resultSet = statement.executeQuery(sql);//返回结果,封装了所有我们全部查询出的结果
//不知道列类型情况下使用
resultSet.getObject();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
遍历
resultSet.beforeFirst();//最前面
resultSet.afterLast();//最后面
resultSet.next();//下一个
resultSet.previous();//前一个
resultSet.absolute(row);//移动到指定行
释放资源
//5.释放链接
resultSet.close();
statement.close();
connection.close();//消耗资源,用完关掉
四、statement对象
CRUD操作-insert
Statement st = connection.createStatement();
String sql="insert into user(...) values(...)";
int num=st.executeUpdate(sql);
if (num>0){
System.out.println("插入成功!!!");
}
CRUD操作-delete
Statement st = connection.createStatement();
String sql="delete from user where id =1";
int num=st.executeUpdate(sql);
if (num>0){
System.out.println("删除成功!!!");
}
CRUD操作-update
Statement st = connection.createStatement();
String sql="update user set name='' where name='' ";
int num=st.executeUpdate(sql);
if (num>0){
System.out.println("修改成功!!!");
}
CRUD操作-read
Statement st = connection.createStatement();
String sql="select * from user where id=1 ";
ResultSet rs=st.executeUpdate(sql);
if (num>0){
//根据返回的数据类型,分别调用rs的相应方法映射到java对象中
}
代码实现
1、提取工具类
2、编写增查删改,excuteUpdate
/excuteQuery
//增删改
public static void main(String[] args){
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn = JdbcUtils.getConnection();
st=conn.createStatement();
String sql="INSERT INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)" +
"VALUES(4,'kuangshen','123456','543682418@qq.com','2020-01-01')";
int n=st.executeUpdate(sql);
if (n>0){
System.out.println("插入成功!!!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
//查
public static void main(String[] args) {
Connection conn=null;
Statement st=null;
ResultSet rs=null;
try {
conn = JdbcUtils.getConnection();
st=conn.createStatement();
String sql="SELECT * FROM users WHERE id=3";
rs=st.executeQuery(sql);
while (rs.next()){
System.out.println(rs.getString("id"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
SQL注入问题
sql存在漏洞,会被攻击导致数据泄露,SQL会被拼接 or
String sql="SELECT * FROM users WHERE `NAME`=' ' or '1=1' AND `PASSWORD`='' or '1=1'";
五、PreparedStatement对象
PreparedStatement可以防止SQL注入并且高效
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
try {
conn=JdbcUtils.getConnection();
//区别
//使用?占位符代替参数
String sql="insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`)values(?,?,?,?,?)";
st=conn.prepareStatement(sql);//预编译sql
//手动参数赋值
st.setInt(1,2);
st.setString(2,"朱飞宇");
st.setString(3,"123456");
st.setString(4,"3215125@qq.com");
//注意点:sql.Date 数据库 java.sql.Date
// util.Date java new Date().getTime()
st.setDate(5,new java.sql.Date(new Date().getTime()));
//执行
int n=st.executeUpdate();
if (n>0){
System.out.println("插入成功!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
六、IDEA连接数据库
-
Step1:连接数据库
-
Step2:连接成功后可以选择数据库
-
Step3:双击数据库
-
Step4:写SQL的地方
七、事务
要么都成功要么都失败
ACID 原则
原子性:要么全部完成要么都不完成
一致性:总数不变
隔离性:多个进程互不干扰
持久性:一旦提交不可逆,持久化到数据库
隔离性的问题:
脏读:一个事务读取了另一个没有提交的事务。
不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变。
虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后结果不一致。
public static void main(String[] args) {
Connection conn=null;
PreparedStatement st=null;
ResultSet rs=null;
try {
conn=JdbcUtils.getConnection();
//关闭数据库的自动提交,自动会开启事务
conn.setAutoCommit(false);//开启事务
String sql1="update account set money=money-100 where name='A'";
st=conn.prepareStatement(sql1);
st.executeUpdate();
String sql2="update account set money=money+100 where name='B'";
st=conn.prepareStatement(sql2);
st.executeUpdate();
//业务完毕提交事务
conn.commit();
System.out.println("成功!");
} catch (SQLException throwables) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
八、数据库连接池
数据库连接和释放是非常浪费资源的,所以现在的池化技术主要是预先准备好资源,用完等待下一个。
- 最小连接数:10
- 最大连接数:100 业务最高承载上线,一旦超过就会排队等待
- 等待超时:100ms 拒绝服务
编写连接池只需要实现一个接口:DateSource
开源数据源实现
DBCP
C3P0
Druid
使用这些数据库连接池后,我们在项目中就不需要编写连接数据库的代码了。
DBCP
需要用到的jar包
commons-dbcp-1.4.jar
commons-pool-1.6.jar
结论
无论使用什么数据源,本质还是一样,DataSource的接口不变