赞
踩
数据库驱动
我们的程序会通过数据库驱动和数据库打交道
Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们通常说的JDBC是面向关系型数据库的。
对于开发人员只需要使用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','zhangsan','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')
然后创建一个名为JDBC的普通java项目
创建一个lib文件夹
导入MySQL Connector/J » 5.1.47的jar包
https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.47
然后右键add as library 点击ok
创建一个class
package com.jdbctest.lesson01; import java.sql.*; public class HelloJdbc { public static void main(String[] args) throws ClassNotFoundException, SQLException { // 加载驱动 // 固定写法 Class.forName("com.mysql.jdbc.Driver"); //用户信息和url String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false"; String username="root"; String password="123456"; // 连接成功数据库对象 Connection connection = DriverManager.getConnection(url, username, password); // 执行sql的对象,去执行sql Statement statement = connection.createStatement(); String sql = "SELECT * FROM users"; // 结果集封装了我们全部的查询结果 ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()){ System.out.println(resultSet.getObject("id")); System.out.println(resultSet.getObject("NAME")); System.out.println(resultSet.getObject("PASSWORD")); System.out.println(resultSet.getObject("email")); System.out.println(resultSet.getObject("birthday")); } // 释放连接 resultSet.close(); statement.close(); connection.close(); } }
DriverManager
// 加载驱动
Class.forName("com.mysql.jdbc.Driver"); //固定写法
URL
//jdbc:mysql://主机名:端口号/数据库名?参数1&参数2
String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8";
statement 执行sql的对象
statement.executeQuery(); // 查询
statement.execute(); //执行任何sql
statement.executeUpdate(); //更新 插入 删除都用这个,返回一个受影响行数
ResultSet 查询结果集,封装了所有的查询结果
//和数据库中的类型一一匹配
resultSet.getObject(); // 不知道列类型的情况下使用
// 如果知道列的类型就使用指定的类型
resultSet.getString();
resultSet.getDate();
resultSet.getInt();
resultSet.getDouble();
遍历指针
resultSet.beforeFirst(); //移动到最前面
resultSet.afterLast(); //移动到最后面
resultSet.next() // 移动到下一个
resultSet.previous(); // 移动到上一个
resultSet.absolute(); // 移动到指定行
释放资源
// 释放连接 十分耗费资源
resultSet.close();
statement.close();
connection.close();
JDBC中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement st = connection.createStatement();
String sql = "insert into user(...)value(...)";
int num = st.executeUpdate(sql);
if(num>0){
System.out.println("插入成功!");
}
CRUD操作-delete
使用executeUpdate(String sql)方法完成数据删除操作,示例操作:
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
使用executeUpdate(String sql)方法完成数据修改操作,示例操作:
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
使用executeUpdate(String sql)方法完成数据查询操作,示例操作:
Statement st = connection.createStatement();
String sql = "select * from user where id=1";
ResultSet rs = st.executeQuery(sql);
while ( rs.next()){
//根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
}
首先在src目录下创建一个db.properties
driver = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&useSSL=true
username =root
password=123456
在创建一个工具类
package com.jdbctest.lesson02.utils; import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class JdbcUtils { private static String driver; private static String url; private static String username; private static String password; static { try{ InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"); Properties properties = new Properties(); properties.load(in); driver= properties.getProperty("driver"); url= properties.getProperty("url"); username= properties.getProperty("username"); password= properties.getProperty("password"); Class.forName(driver); } catch (Exception e) { e.printStackTrace(); } } //获取连接 public static Connection getConnection()throws SQLException{ return DriverManager.getConnection(url,username,password); } //释放连接资源 public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException { if(rs!=null) { rs.close(); } if(st!=null){ st.close(); } if (conn!=null){ conn.close(); } } }
再创建测试类
package com.jdbctest.lesson02; import com.jdbctest.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Test { public static void main(String[] args) { Connection conn=null; Statement st =null; ResultSet rs=null; try{ conn= JdbcUtils.getConnection();//获取连接 st=conn.createStatement();//获取sql的执行对象 // //插入数据 // String sql="INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES ('4','xiaobai','123456','789456158@qq.com','2021-10-22')"; // int i=st.executeUpdate(sql); // if(i>0){ // System.out.println("插入成功"); // } //删除数据 // String sql="DELETE FROM users WHERE id=4"; // int i=st.executeUpdate(sql); // if(i>0){ // System.out.println("删除成功"); // } //更新数据 // String sql="UPDATE users SET `NAME`='xiaohei' WHERE id=1"; // int i=st.executeUpdate(sql); // if(i>0){ // System.out.println("修改成功"); // } //查询数据 String sql="select * from users"; rs=st.executeQuery(sql); while (rs.next()){ System.out.println(rs.getObject("id")); System.out.println(rs.getObject("NAME")); System.out.println(rs.getObject("PASSWORD")); System.out.println(rs.getObject("email")); System.out.println(rs.getObject("birthday")); } } catch (SQLException e) { e.printStackTrace(); } } }
web程序代码中对于用户提交的参数未做过滤就直接放到SQL语句中执行,导致参数中的特殊字符打破了SQL语句原有逻辑,黑客可以利用该漏洞执行任意SQL语句.
1.是一种将SQL语句插入或添加到应用(用户)的输入参数中的攻击
2.这些参数传递给后台的SQL数据库服务器加以解析并执行.
SQL注入的本质是恶意攻击者将SQL代码插入或添加到程序的参数中,而程序并没有对传入的参数进行正确处理,导致参数中的数据会被当做代码来执行,并最终将执行结果返回给攻击者
1、数据库信息泄露:数据库中存放的用户的隐私信息的泄露
2、网页串改:通过数据库对特定的网页进行篡改(网页内容存储在数据库,通过修改内容达到网页篡改)
3、网站挂马,传播恶意软件:通过修改数据库一些字段的值,嵌入网马链接,进行网马攻击
4、数据库被恶意操作:数据库被攻击,数据库的系统管理员账户被篡改
5、获取webshell:利用数据库存在的权限分配缺陷获取webshell甚至是系统权限
package com.jdbctest.lesson02; import com.jdbctest.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class TestInject { public static void main(String[] args) throws SQLException { login("'or' 1=1","'or' 1=1"); } public static void login(String username,String password) throws SQLException { Connection conn=null; Statement st =null; ResultSet rs=null; try{ conn= JdbcUtils.getConnection();//获取连接 st=conn.createStatement();//获取sql的执行对象 //SELECT * FROM `users` WHERE `NAME`= "+"'"+username+"'"+" AND `PASSWORD`="+"'"+password+"' String sql="SELECT * FROM `users` WHERE `NAME`= "+"'"+username+"'"+" AND `PASSWORD`="+"'"+password+"'"; rs=st.executeQuery(sql); while (rs.next()){ System.out.println(rs.getObject("NAME")); System.out.println(rs.getObject("PASSWORD")); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
PreparedStatement可以防止SQL注入,更安全
package com.jdbctest.lesson03; import com.jdbctest.lesson02.utils.JdbcUtils; import java.sql.*; import java.util.Date; public class TestPS { public static void main(String[] args) throws SQLException { Connection conn=null; PreparedStatement st =null; ResultSet rs=null; try{ conn= JdbcUtils.getConnection();//获取连接 // //插入数据 // //使用?占位符代替参数 // String sql="INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (?,?,?,?,?)"; // //预编译mysql,先写sql,然后不执行 // st=conn.prepareStatement(sql); // //手动给参数复制 // st.setInt(1,4); // st.setString(2,"xiaohei"); // st.setString(3,"123456"); // st.setString(4,"789524631@qq.com"); // // 注意点:sql.date 数据库 // // util.Date new Date().getTime() 获取时间戳 // st.setDate(5,new java.sql.Date(new Date().getTime())); // int i=st.executeUpdate(); // if(i>0){ // System.out.println("插入成功"); // } //删除数据 // String sql="DELETE FROM users WHERE id=?"; // st = conn.prepareStatement(sql); // st.setInt(1,4); // int i=st.executeUpdate(); // if(i>0){ // System.out.println("删除成功"); // } //更新数据 // String sql="UPDATE users SET `NAME`=? WHERE id=?"; // st=conn.prepareStatement(sql); // st.setString(1,"xiaohei"); // st.setInt(2,1); // // int i=st.executeUpdate(); // if(i>0){ // System.out.println("修改成功"); // } //查询数据 String sql="SELECT * FROM `users` where id=?"; st=conn.prepareStatement(sql); st.setInt(1,1); rs=st.executeQuery(); while (rs.next()){ System.out.println(rs.getObject("id")); System.out.println(rs.getObject("NAME")); System.out.println(rs.getObject("PASSWORD")); System.out.println(rs.getObject("email")); System.out.println(rs.getObject("birthday")); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
防止sql注入
package com.jdbctest.lesson03; import com.jdbctest.lesson02.utils.JdbcUtils; import java.sql.*; public class TestPSInject { public static void main(String[] args) throws SQLException { // login("lisi","123456"); login("'' or 1=1", "'' or 1=1"); } public static void login(String username, String password) throws SQLException { Connection conn = null; PreparedStatement st = null; ResultSet rs = null; try { conn = JdbcUtils.getConnection();//获取连接 //st = conn.createStatement();//获取sql的执行对象 //SELECT * FROM `users` WHERE `NAME`= "+"'"+username+"'"+" AND `PASSWORD`="+"'"+password+"' String sql = "SELECT * FROM `users` WHERE `NAME`=? and `PASSWORD`=?"; // PreparedStatement防l:SQL注入的本质,把传递进来的参数当做字符 // 假设其中存在转义字符,就直接忽略, st=conn.prepareStatement(sql); st.setString(1,username); st.setString(2,password); rs = st.executeQuery(); while (rs.next()) { System.out.println(rs.getObject("NAME")); System.out.println(rs.getObject("PASSWORD")); System.out.println("======================="); } } catch (SQLException e) { e.printStackTrace(); } finally { JdbcUtils.release(conn, st, rs); } } }
创建数据库
创建查询
更新数据库
切换数据库
原子性: 要么全都成功,要么全都失败
一致性: 结果不变,总数一直
隔离性: 多个进程互不干扰
持久性: 一旦提交不可逆,持久化到数据库了
隔离性的问题:
脏读 :一个事务读取了另一个没有提交的事务
不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变
虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来的结果不一致
代码实现
package com.jdbctest.lesson04; import com.jdbctest.lesson02.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TestTransation { public static void main(String[] args) throws SQLException { 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 (Exception e) { //回滚 conn.rollback(); e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
数据库连接–执行完毕–释放 十分浪费系统资源
池化技术:准备一些预先的资源,过来就连接预先准备好的
最小连接数: 10
最大连接数:20
等待超时:100ms
编写连接池,实现一个接口 DataSource
开源数据源实现
DBCP
C3P0
Druid:阿里巴巴
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了!
DBCP
需要用到的jar包都可以在阿里云仓库找到 commons-dbcp-1.4.jar commons-pool-1.6.jar
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123456 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=UTF8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
package com.jdbctest.lesson05.utils; import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class jdbcutils_dbcp { private static DataSource source=null; static { try { InputStream in =jdbcutils_dbcp.class.getClassLoader().getResourceAsStream("dbconfig.properties"); Properties properties = new Properties(); properties.load(in); //创建数据源 工厂模式--> 创建对象 source = BasicDataSourceFactory.createDataSource(properties); }catch (Exception e){ e.printStackTrace(); } } // 获取连接 public static Connection getConnection() throws SQLException { //从数据源中获取连接 return source.getConnection(); } //释放连接资源 public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException { if(conn!=null) conn.close(); if(st!=null) st.close(); if(rs!=null) rs.close(); } }
测试
package com.jdbctest.lesson05; import com.jdbctest.lesson05.utils.jdbcutils_dbcp; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class test { public static void main(String[] args) throws SQLException { Connection connection=null; PreparedStatement statement=null; ResultSet rs=null; try { //获取连接 connection = jdbcutils_dbcp.getConnection(); //sql String sql="SELECT * from users WHERE id=?"; //预编译sql statement= connection.prepareStatement(sql); //设置参数 statement.setObject(1,1); //执行sql rs=statement.executeQuery(); //遍历结果 while (rs.next()){ System.out.println(rs.getObject("NAME")); } } catch (SQLException e) { e.printStackTrace(); }finally { jdbcutils_dbcp.release(connection,statement,rs); } } }
导入jar包 c3p0-0.9.1.2.jar mchange-commons-java-0.2.9.jar
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!-- c3p0的缺省(默认)配置 如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource();"这样写就表示使用的是c3p0的缺省(默认)--> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&uesSSL=true&serverTimezone=UTC</property> <property name="user">root</property> <property name="password">123456</property> <property name="acquiredIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </default-config> <!-- c3p0的命名配置 如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");"这样写就表示使用的是mysql的缺省(默认)--> <named-config name="MySQL"> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&uesSSL=true&serverTimezone=UTC</property> <property name="user">root</property> <property name="password">123456</property> <property name="acquiredIncrement">5</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">5</property> <property name="maxPoolSize">20</property> </named-config> </c3p0-config>
配置
package com.jdbctest.lesson05.utils; import com.mchange.v2.c3p0.ComboPooledDataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class jdbcutils_c3p0 { private static ComboPooledDataSource source=null; static { try { source= new ComboPooledDataSource("MySQL"); //创建数据源 工厂模式--> 创建对象 }catch (Exception e){ e.printStackTrace(); } } // 获取连接 public static Connection getConnection() throws SQLException { //从数据源中获取连接 return source.getConnection(); } //释放连接资源 public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException { if(conn!=null) conn.close(); if(st!=null) st.close(); if(rs!=null) rs.close(); } }
测试
package com.jdbctest.lesson05; import com.jdbctest.lesson05.utils.jdbcutils_c3p0; import com.jdbctest.lesson05.utils.jdbcutils_dbcp; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class Test2 { public static void main(String[] args) throws SQLException { Connection connection=null; PreparedStatement statement=null; ResultSet rs=null; try { //获取连接 connection = jdbcutils_c3p0.getConnection(); //sql String sql="SELECT * from users WHERE id=?"; //预编译sql statement= connection.prepareStatement(sql); //设置参数 statement.setObject(1,1); //执行sql rs=statement.executeQuery(); //遍历结果 while (rs.next()){ System.out.println(rs.getObject("NAME")); } } catch (SQLException e) { e.printStackTrace(); }finally { jdbcutils_dbcp.release(connection,statement,rs); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。