SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个java操作数据库的规范,俗称JDBC
这些规范的实现由具体的厂商去做,对于开发人员来说,我们只需要掌握JDBC接口的操作即可
jdbc需要的jar包
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>mchange-commons-javaartifactId>
<version>0.2.19version>
dependency>
<dependency>
<groupId>commons-poolgroupId>
<artifactId>commons-poolartifactId>
<version>1.6version>
dependency>
<dependency>
<groupId>commons-dbcpgroupId>
<artifactId>commons-dbcpartifactId>
<version>1.4version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.5version>
dependency>
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,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')
package com.qian.jdbc;
import java.sql.*;
//我的第一个jdbc程序
public class jdbcFirst {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动
//2.用户信息和url
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对象 Statement 执行SQL的对象
Statement statement = connection.createStatement();
//5.用执行SQL的对象执行SQL,可能存在结果,查看返回结果
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("====================================================");
}
//6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
运行,拿到数据
步骤总结:
Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动
Connection connection = DriverManager.getConnection(url, username, password); //连接到数据库
//connection --数据库
connection.rollback(); // 事务回滚
connection.commit(); //事务提交
connection.setAutoCommit(); // 数据库设置自动提交
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
//jdbc:mysql://主机地址:3306/数据库名?参数1&参数2&参数3
//mysql--3306
//oralce --1521
// 执行SQL的对象 ,preparestatement也是执行sql的对象
String sql = "SELECT *FROM users";//编写SQL
statement.executeQuery();//查询操作返回 resultset
statement.execute();//执行任何SQL
statement.executeUpdate();//更新、插入、删除,都是用这个,返回一个受影响的行数
4.ResultSet
//只有查询才会返回的结果集,封装了所有查询出来的数据
resultSet.getObject(); //不知道列类型的情况下使用
resultSet.getInt(); //知道列的类型就使用指定的类型
resultSet.getBoolean();
resultSet.getFloat();
resultSet.getDate();
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后面
resultSet.next(); //移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行
//6.释放连接
resultSet.close();
statement.close();
connection.close();
Statement st = conn.createStatement();
String sql = "insert into user()values()";
int num = st.excuteUpdate(sql);
if(num>0){
system.out.println("插入成功");
} // 只要影响的数据发生变化则插入成功
Statement st = conn.createStatement();
String sql = "delete from user where id=1";
int num = st.excuteUpdate(sql);
if(num>0){
system.out.println("删除成功");
}
Statement st = conn.createStatement();
String sql = "update user set name=''where name=''";
int num = st.excuteUpdate(sql);
if(num>0){
system.out.println("修改成功");
}
Statement st = conn.createStatement();
String sql = "SELECT *FROM users";
ResultSet resultSet = st.executeQuery(sql)
while (resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));}
"select * from s_student where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"'";
1
然后我随便输入一个用户名,但是只要密码输入的有讲究点
loginName = fasd;
loginPwd = fasd' or '1'='1;
12
因为1=1这条语句是一个永真式,且逻辑连接词使用的or,这样一来无论前面是什么loginPwd这个值一定为1,这样就将前面select语句的where条件恒为1,就相当于将前面的select语句给废了。
String Sql="select * from s_student where loginName = '"+fasd+"' and loginPwd = '"+fasd' or '1'='1+"'";
1
这样子我们可以绕过登录,去做一些危害网站的事情。
其实发生SQL注入的根本原因并非 是我们编写了loginPwd = fasd’ or ‘1’=‘1这条语句,究其根本是因为fasd’ or ‘1’='1这条语句被当作了sql语句的一部分被编译进去了
rs = stam.executeQuery(sql);
1
程序在执行到上面这行语句时,会将sql语句发送给DBMS(数据库管理系统),然后DBMS会将sql语句进行编译,但此时已经晚了,因为此时用户已经将一些非法语句拼接进了sql语句当中去,这样就会发生SQL注入。
PreparedStatement可以防止SQL注入,效率更好
我们可以事先将sql语句传入PreparedStatement中,将要传入到sql语句中的参数使用?(占位符)来代替,那么该sql语句就会进行预编译,之后将获取的参数通过PreparedStatement中的set(类型)方法传入编译后的sql语句中,这样sql语句就会先被编译再进行传值,用户输入的信息不会直接参与到sql语句的编译当中,就防止了sql注入的问题。
ps = conn.prepareStatement("select * from s_student where name = ? and password = ?");//先预编译
//一个问号表示一个占位符将来接收一个值
ps.setString(1,loginName);
ps.setString(2,loginPwd);
rs = ps.executeQuery(); // 执行查询
//把配置以及关闭资源放在一个java类里utils.jdbcUtils
private static String url="jdbc:mysql://localhost:3306/test";
private static String username="root";
private static String password="root";
static{
Class.forName("com.mysql.jdbc.Driver");
}
public static Connection getConn(){
Connection connection=DriverManager.getConnection(url,username,password);
return connection;
}
//关闭资源
public static void close(ResultSet rs,Perparedstment perparedstment,Connection conn){
if(!Objects.isNull(rs)){rs.close();}
if(!Objects.isNull(perparedstment)){perparedstment.close()}
if(!Objects.isNull(conn)){conn.close();}
}
}
//插入操作
package com.qian;
import com.qian.utils.jdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test01 {
public static void main(String[] args) throws SQLException {
Connection connection= null;
PreparedStatement pstm=null;
try {
connection = jdbcUtils.getConnection();
//区别
//使用问好占位符代替参数
String sql = "insert into users(id,`NAME`) values(?,?)";
pstm = connection.prepareStatement(sql);//预编译sql,先写sql然后不执行
//手动赋值
pstm.setInt(1,6);
pstm.setString(2,"SANJIN");
//执行
int i = pstm.executeUpdate();
if (i>0){
System.out.println("插入成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
jdbcUtils.release(connection,pstm,null);
}
}
}
原子性、一致性、隔离性、持久性
package com.qian.jdbc;
import com.qian.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args) throws SQLException {
Connection conn1 =null;
PreparedStatement st=null;
ResultSet rs = null;
try {
conn1 = JdbcUtils.getConn();
//关闭数据库的自动提交功能,自动会开启事务
conn1.setAutoCommit(false);
//
String sql1 ="update account set money-100 where name ='A'";
st = conn1.prepareStatement(sql1);
st.executeUpdate();
String sql2 ="update account set money+100 where name ='B'";
st = conn1.prepareStatement(sql2);
st.executeUpdate();
//业务完毕,提交事务
conn1.commit();
System.out.println("成功");
} catch (SQLException e) {
try {
conn1.rollback();//如果失败则回滚事务
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.close(rs,st, conn1);
}
}
}
-----开门–业务员:等待 – 服务—
常用连接数 10个
最小连接数:10
最大连接数 15 业务最高承载上限
排队等候,等待超时:…
编写连接池,实现一个接口 DataSource
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了!
<dependency>
<groupId>commons-poolgroupId>
<artifactId>commons-poolartifactId>
<version>1.6version>
dependency>
<dependency>
<groupId>commons-dbcpgroupId>
<artifactId>commons-dbcpartifactId>
<version>1.4version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>mchange-commons-javaartifactId>
<version>0.2.19version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.5version>
dependency>