- 概念
- Java database Connectivity Java数据库连接,即通过Java访问数据库。
- 本质:官方定义的接口,有各个数据库厂商实现这个接口,提供数据库驱动jar包。我们使用这套接口编程。
- 使用:
1导入驱动jar包 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar- 注册驱动
* Calss.forname(“com.mysql.jdbc.Driver”);- 理解:实际上就是告知程序该使用哪个驱动jar包。Class.forname实际上是利用反射,将该类加载到内存中,加载的时候会执行其中的静态代码块,完成初始化的相关工作。
static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
- 理解:实际上就是告知程序该使用哪个驱动jar包。Class.forname实际上是利用反射,将该类加载到内存中,加载的时候会执行其中的静态代码块,完成初始化的相关工作。
- 获取数据库连接对象
* Connection conn = DriverMannager.getConnection(url, user, paaword) ;- 理解:利用DiverManager中的getConnection(String url, String user, String password)方法,尝试建立与给定数据库URL的连接。 DriverManager尝试从一组已注册的JDBC驱动程序中选择适当的驱动程序。
- 获取执行sql对象
* Statement stmt = conn.createStatement();- 理解: 调用数据库连接对象的createStatement()方法获取执行sql语句的对象
- 执行sql语句
* stmt.excuteUpdate(sql); //用来执行增删改语句
* stmt.excuteQuery(sql); //用来执行查询语句
- 注册驱动
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
*设计一个方法
*public static void execute(String sql)
*方法接受的参数是SQL语句,无论是增加,删除,还是修改,都调用这个方法,每次传不同的SQL语句作为参数
*/
public class Exercise_01 {
public static void main(String[] args) {
//定义sql语句
//增加
String sql = "insert into account values(null,'路飞',1000)";
//删除
String sql2 = "delete from account where id = 3";
//改
String sql3 = "update account set balance = 2000 where id =1";
//调用方法执行sql语句
Exercise_01.execute(sql);
Exercise_01.execute(sql2);
Exercise_01.execute(sql3);
}
//需求的方法
public static void execute(String sql) {
//注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try(
//获取连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql:///db3", "root","root");
//获取执行sql对象
Statement stmt = conn.createStatement();
) {
//执行sql
stmt.executeUpdate(sql);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- JDBC查询
- 查询需要用到excuteQuery();该方法返回的是ResultSet对象。
- ResultSet类详解:
- 结果集对象,用来封装查询结果。
- 方法:
- boolean next() 游标向下移动一行,判断当前行是否是最后一行的末尾(是否有数据),是返回false,不是则返回true。
- getXxx(参数):
- XXX代表数据类型:getInt(), getDouble(), getString()。
- 参数
- int :代表列的编号,从1开始 如:getString(1)
- String : 代表列的名称。如:getDouble("balance”)
- 使用步骤:
- 游标向下移动一行
- 判断是否有数据
- 获取数据(一般用while循环来判断是否在最后一行末尾)
- ResultSet类详解:
- 查询需要用到excuteQuery();该方法返回的是ResultSet对象。
public class JDBCDemo7 {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象
conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
//3.定义sql
String sql = "select * from account";
//4.获取执行sql对象
stmt = conn.createStatement();
//5.执行sql
rs = stmt.executeQuery(sql);
//6.处理结果
//循环判断游标是否是最后一行末尾。
while(rs.next()){
//获取数据
//6.2 获取数据
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble(3);
System.out.println(id + "---" + name + "---" + balance);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//7.释放资源
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
- JDBC预编译Statement
- PrepareStatement类详解:
- 和Statement一样,PrepareStatement也是用来执行sql语句的,不同的是,创建PrepareStatement对象的时候把sql语句当做参数传递进去。
- 优点:
- 可以通过设置参数,指定sql语句相应变量的值。
* Statement 需要进行字符串拼接,可读性和维护性比较差
String sql = “insert into hero values(“select * from account where id = '”+id+’”, name = ‘"+name+"’")";
* PreparedStatement 使用参数设置,可读性好,不易犯错
String sql = “insert into hero values(null,?,?,?)”; - PrepareStatement有预编译机制,性能比Statement快,效率更高。
- Statement每次执行,需要把每个sql语句传输到数据端,数据库需要对每一次来的sql语句进行编译处理。
- PrepareStatement每次执行,只需要一次把sql语句传入到数据库端,数据库对带?的sql进行预编译,每次执行,只需要传输参数到数据库端,网络传输量比sql更小,数据库不需要再重新进行编译,响应更快。
- PrepareStatement 可以解决注入的问题
* SQL注入问题:在拼接sql时候,有一些sql特殊的关键词参与字符串拼接,会造成安全问题。
* 登录问题:
例如:
* 用户随便输入密码:password’ or ‘password’ = 'password
* sql语句:select * from user where name = ‘user’ and password = ‘password’ or ‘password’ = 'password’由于恒成立,故则会导致登录成功。
* 内存占用:
例如:
* 用户提交的数据为:String name = “‘路飞’ or 1 = 1”;
* 使用Statement的话拼接出来的sql语句是:select * from onepeace where name = ‘路飞’ or 1 = 1 由于有or 1 = 1,恒成立,故会查询数据库表中的所有数据,如果表中的数据炒鸡多,那么就会使得CPU的负载过高,进而使得响应变得及其缓慢。而PrepareStatement为参数设置,就不存在这样的问题。
- 可以通过设置参数,指定sql语句相应变量的值。
- 使用步骤:
- 导入驱动jar包:mysql-connector-java-5.1.37-bin.jar
- 注册驱动
- 获取数据库连接对象Connection
- 定义sql
* 注意: sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?; - 获取执行sql语句的对象PrepareStatement
- 给?赋值:
- 方法:setXxx(参数一,参数二)
- 参数一:?的位置编号,从一开始
- 参数二:?的值
- 方法:setXxx(参数一,参数二)
- 执行sql
- 处理结果
- 释放资源
- PrepareStatement类详解:
import java.sql.*;
/**
* 测试PreparedStatement的优点:注入式问题
*/
public class TestJDBC04 {
public static void main(String[] args) {
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String sql1 = "select * from account where name = ?";
try(
//获取连接数据库的对象
Connection conn = DriverManager.getConnection("jdbc:mysql:///db3","root","root");
//利用Statement获取执行sql对象
Statement stmt = conn.createStatement();
//利用PrepareStatement来获取执行对象
PreparedStatement preStmt =conn.prepareStatement(sql1);
) {
//定义sql
String select_name = "lisi";
String sql2 = "select * from account where name = '"+select_name+"'or 1 = 1";
//执行sql
ResultSet rs = stmt.executeQuery(sql2);
//打印结果
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
double balance = rs.getDouble("balance");
System.out.println("id:" + id + "\nname:" + name + "\nbalance:" + balance);
System.out.println("\n");
} //打印出了表中所有的数据
System.out.println("====================");
//利用PrepareStatement来获取的对象来执行sql语句
preStmt.setString(1,select_name);
ResultSet rs2 = preStmt.executeQuery();
//再次查询
while (rs2.next()) {
int id = rs2.getInt("id");
String name = rs2.getString("name");
double balance = rs2.getDouble("balance");
System.out.println("id:" + id + "\nname:" + name + "\nbalance:" + balance);
System.out.println("\n");
} //子查询出了一条数据
} catch (SQLException e) {
e.printStackTrace();
}
}
}
-
excute和excuteUpdate区别
- 相同点:都可以执行增,删,改。
- 不同点:
- excute可以执行查询语句。然后可以通过getResult,把结果集取出来。excuteUpdate不能执行查询语句。
- excute返回的是boolean类型,true表示的是查询语句,false表示的是insert,delete,update等语句。excuteUpdate返回的是int,表示有多少条数据受到了影响。
-
JDBC特殊操作—获取自增长id以及表的元数据
- 获取自增长id
* 在Statement通过execute或者executeUpdate执行完插入语句后,MySQL会为新插入的数据分配一个自增长id,(前提是这个表的id设置为了自增长,在Mysql创建表的时候,AUTO_INCREMENT就表示自增长)
CREATE TABLE hero (
id int(11) AUTO_INCREMENT,
}
但是无论是execute还是executeUpdate都不会返回这个自增长id是多少。(excute返回执行的语句类型,true表示的是查询,false表示的是insert,update等,excuteUpdate返回的是影响的行数。)需要通过Statement的getGeneratedKeys获取该id
- 获取自增长id
import java.sql.*;
public class JDBCDemo05 {
public static void main(String[] args) {
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");//总是在这里忘记加;号了,注意!!!
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//定义sql语句
String sql = "insert into account values(null, '索隆',5000)";
try(
//获取连接数据库对象
Connection conn = DriverManager.getConnection("jdbc:mysql:///db3","root","root");//忘记传入账号密码了
//获取执行sql的对象
PreparedStatement pstm = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//进行预编译
) {
//执行sql
pstm.executeUpdate();
//通过getGenartedekeys()获取id
ResultSet rs = pstm.getGeneratedKeys();
while(rs.next()){
int id = rs.getInt(1);
System.out.println("加入的信息的id为:" + id);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 获取表的元数据
* 概念:和数据库服务器相关的概念,比如数据库版本,有哪些列表,字段类型是什么等等。
import java.sql.*;
public class JDBCDemo06 {
public static void main(String[] args) {
try {
//注册驱动
Class.forName("com.mysql.jdbc.Driver");//总是在这里忘记加;号了,注意!!!
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//定义sql语句
String sql = "insert into account values(null, '索隆',5000)";
try(
//获取连接数据库对象
Connection conn = DriverManager.getConnection("jdbc:mysql:///db3","root","root");//忘记传入账号密码了
) {
//查看数据库层面的元数据
DatabaseMetaData dbmd = conn.getMetaData();
//获取数据库服务器产品的名称
System.out.println("数据库产品的名称为:" + dbmd.getDatabaseProductName());
//获取数据库服务器产品的版本号
System.out.println("数据库服务器产品的版本号为:" + dbmd.getDatabaseProductVersion());
//获取数据库用于作用与类别和表名之间的分隔符
System.out.println("数据库用于作用与类别和表名之间的分隔符为:" + dbmd.getCatalogSeparator());
//获取驱动版本
System.out.println("驱动版本为:" + dbmd.getDriverVersion());
//获取数据库名称
System.out.println("可用的数据库表名称为:");
ResultSet rs = dbmd.getCatalogs();
while (rs.next()) {
System.out.println("数据库名称为:" + rs.getString(1));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- JDBC事务
- 概念:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
- 操作
- 开启事务
- 提交事务
- 回滚事务
- 使用Connection对象来管理事务
- 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
* 在执行sql之前开启事务 - 提交事务:commit()
* 当所有sql都执行完提交事务 - 回滚事务:rollback()
* 在catch中回滚事务
- 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
/**设计一个代码,删除表中前10条数据,但是删除前会在控制台弹出一个提示:
* 是否要删除数据(Y/N)
* 如果用户输入Y,则删除
* 如果输入N则不删除。
* 如果输入的既不是Y也不是N,则重复提示
*/
import java.sql.*;
import java.util.Scanner;
public class Exercise_8_4_demo2 {
public static void main(String[] args) {
//注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//定义sql语句
String sqlDelete = "delete from account where id = ?";
String sqlSelect = "select * from account where id = ? ";
try (
//获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql:///db3","root","root");
//获取执行sql语句对象
PreparedStatement pstmt = conn.prepareStatement(sqlSelect);
PreparedStatement pstmt2 = conn.prepareStatement(sqlDelete);
) {
//开启事务
conn.setAutoCommit(false);
int a = 1; //设置初始ID = 1;
//用for循环找出前十位ID
for (int i = 1; i <= 10; i++) {
while (true) {
pstmt.setInt(1,a);
ResultSet rs = pstmt.executeQuery();
//判断是否有ID存在
if (rs.next()) {
pstmt2.setInt(1,a);
pstmt2.executeUpdate(); //存在就删除
System.out.println("即将删除id = "+ a + " 的数据");
break; //如果存在终止循环
} else {
//不存在则判断下一个ID(a++)
a++;
}
}
}
//提示是否删除信息
while(true) {
System.out.println("是否删除这些数据Y/N:");
Scanner sc = new Scanner(System.in);
String select = sc.nextLine();
if (select.equals("Y")) { //字符串与字符串之间的比较需要用equals()方法。
//关闭事务
conn.commit();
System.out.println("删除成功!");
break;
} else if (select.equals("N")){
System.out.println("取消删除!");
break;
} else {
System.out.println("输入有误,请重新输入!");
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
-
对象和关系数据库的映射-ORM
- ORM(Object Relationship Database Mapping):一个对象对应着数据库里的一条记录。
- DAO(Data Access Object):数据访问对象。
-
数据库连接池
- 其实就是一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库的时候,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器.
- 好处:
- 节约资源
- 用户访问高效.
- 实现:
- 标准接口:dataSource java.sql包下面的.
- 方法:
- 获取连接;getConnection()
- 归还连接;Connection.close.如果连接的对象是从连接池中获取的,那么调用Connection,close()方法,则不会关闭连接了,而是归还连接.
- 方法:
- 标准接口:dataSource java.sql包下面的.
- c3p0数据库连接池
步骤:
1. 导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,不要忘记导入数据库驱动jar包
2. 定义配置文件:
* 名称: c3p0.properties 或者 c3p0-config.xml
* 路径:直接将文件放在src目录下即可。
3. 创建核心对象 数据库连接池对象 ComboPooledDataSource
4. 获取连接: getConnection - Druid:数据库连接池实现技术,由阿里巴巴提供的
步骤:- 导入jar包 druid-1.0.9.jar
- 定义配置文件:
- 是properties形式的
- 可以叫任意名称,可以放在任意目录下
- 加载配置文件。Properties
- 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
- 获取连接:getConnection