jdbc:使用Java代码发送sql语句的技术,就是jdbc技术
1、数据库的连接
jdbc发送sql语句首先得先登录数据服务器
- 数据库的ip地址、端口、要登录的数据库
- 数据库用户名密码
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import org.junit.Test;
public class Demo1 {
// 连接数据库的URL(不同数据库不一样)
private String url = "jdbc:mysql://localhost:3306/jdbcDemo";
// jdbc协议:MySQL子协议://主机:端口/连接数据库
private String user = "root";
private String password = "root";
/**
* jdbc 第一种连接方法
* @throws SQLException
*/
@Test
public void test1() throws SQLException{
// 创建驱动程序类对象
Driver driver = new com.mysql.jdbc.Driver();
// 设置用户名和密码
Properties prop = new Properties();
prop.setProperty("user", user);
prop.setProperty("password", password);
// 连接数据库,返回连接对象
Connection connect = driver.connect(url, prop);
System.out.println(connect);
}
/**
* 使用驱动管理类连接数据库
* @throws SQLException
* @throws ClassNotFoundException
*/
@Test
public void test2() throws SQLException, ClassNotFoundException{
// 通过得到字节码对象的方式加载静态代码块,从而注册驱动程序
// 因为在Driver类的源码中有静态的代码块,里边新建一个Driver类并放入DriverManager中注册
// DriverManager中可以管理多个数据库的驱动
Class.forName("com.mysql.jdbc.Driver");
// 通过这里的url确定获取那个数据库的连接
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
}
2、jdbc核心API
java.sql.* 和 javax.sql.*
|- Driver接口: 表示java驱动程序接口。所有的具体的数据库厂商要来实现此接口。
|- connect(url, properties): 连接数据库的方法。
url: 连接数据库的URL
URL语法: jdbc协议:数据库子协议://主机:端口/数据库
user: 数据库的用户名
password: 数据库用户密码
|- DriverManager类: 驱动管理器类,用于管理所有注册的驱动程序
|-registerDriver(driver) : 注册驱动类对象
|-Connection getConnection(url,user,password); 获取连接对象
|- Connection接口: 表示java程序和数据库的连接对象。
|- Statement createStatement() : 创建Statement对象
|- PreparedStatement prepareStatement(String sql) 创建PreparedStatement对象
|- CallableStatement prepareCall(String sql) 创建CallableStatement对象
|- Statement接口: 用于执行静态的sql语句
|- int executeUpdate(String sql) : 执行静态的更新sql语句(DDL,DML)
|- ResultSet executeQuery(String sql) :执行的静态的查询sql语句(DQL)
|-PreparedStatement接口:用于执行预编译sql语句
|- int executeUpdate() : 执行预编译的更新sql语句(DDL,DML)
|-ResultSet executeQuery() : 执行预编译的查询sql语句(DQL)
|-CallableStatement接口:用于执行存储过程的sql语句(call xxx)
|-ResultSet executeQuery() : 调用存储过程的方法
|- ResultSet接口:用于封装查询出来的数据
|- boolean next() : 将光标移动到下一行
|-getXX() : 获取列的值
1)、使用Statement执行sql语句
/**
*
* 创建一个表
* @throws ClassNotFoundException
*
*/
@Test
public void test1(){
Connection connection = null;
Statement statement = null;
try {
//1、 注册驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 2、获取连接对象
connection = DriverManager.getConnection(url, user, password);
// 3、创建Statement对象
statement = connection.createStatement();
// 4、准备sql
String sql = "CREATE TABLE stu(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20));";
// 5、发送sql,执行sql语句,得到返回结果
int count = statement.executeUpdate(sql);
// 6、输出
System.out.println("影响了"+count+"行");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
if(statement!=null)
try {
statement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException(e);
}
if(connection!=null)
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
/**
* 查询
*/
@Test
public void test2(){
Connection con = null;
Statement stm = null;
try{
//1、 注册驱动程序
Class.forName("com.mysql.jdbc.Driver");
// 2、获取连接对象
con = DriverManager.getConnection(url, user, password);
// 3、创建Statement对象
stm = con.createStatement();
// 4、准备sql
String sql = "select * from stu;";
// 5、执行查询
ResultSet rs = stm.executeQuery(sql);
while(rs.next()){
// 根据列索引取值,从1开始
int id = rs.getInt(1);
String name = rs.getString(2);
System.out.println("根据索引取值:id="+id+" name="+name);
// 根据列名取值
int i = rs.getInt("id");
String na = rs.getString("name");
System.out.println("根据列名取值:id="+i+" name="+na);
}
}catch (Exception e) {
e.printStackTrace();
}finally{
if(stm!=null)
try {
stm.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(con!=null)
try {
con.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
2)使用PreparedStatement执行sql语句
/**
* 添加数据
*/
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url, user, password);
String sql = "insert into stu(id,name) values(?,?);";
pstm = con.prepareStatement(sql);
pstm.setInt(1, 6);
pstm.setString(2,"索取");
pstm.executeUpdate();
// 查询数据
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url, user, password);
String sql = "select * from stu where id=?";
pstm = con.prepareStatement(sql);
pstm.setInt(1, 5);
ResultSet rs = pstm.executeQuery();
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString(2);
System.out.println("id="+id+" name="+name);
}
Statement和PreparedStatement区别
原理:
SQL语句首先执行语法检测,权限检测,然后放入数据库的缓冲区,等待数据库读取,数据库从缓冲区读取sql语句执行。
Statement由于参数都是先写定的例如select * from stu where id=2
和select * from stu where id=3
,这两个sql语句在Statement中会认为是两条语句,但在PreparedStatement中select * from stu where id=?
就会是一条sql语句放在sql缓冲区中,只需要更改参数执行。
区别:
- PreParedStatement比Statement更加高效(这是指在有缓冲区的数据库,Mysql没有缓冲区)
- 语法不一样
- PreparedStatement可以防止sql注入
SQL注入:执行静态sql语句时发生
例如:
String str = "select * from stu where user="+user+" && possword="+possword;
id为用户输入值,当用户输入abc or 1=1 --
时会查出所有用户数据
3) CallableStatement执行存储过程
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection(url, user, password);
String sql = "CALL pro_findById(?,?);";
// 返回一个CallableStatement
cstm = con.prepareCall(sql);
// 设置参数
cstm.setInt(1, 2);
// 设置输出参数
/**
* 参数位置,存储过程中的输出参数的jdbc类型
*/
cstm.registerOutParameter(2, java.sql.Types.VARCHAR);
// 发送参数执行
cstm.executeQuery(); // 结果返回到输出参数中
// 获取返回值
String str = cstm.getString(2);
System.out.println(str);
4). 插入数据,获取自增长值
需求:员工表,部门表,员工表有外键指向部门,需要插入一个部门,并对员工表插入一个员工属于新部门,所以插入部门时要获取部门的id
// 保存员工,同时保存关联的部门
public void save(Employee emp){
// 保存部门
String sql_dept = "insert into dept(deptName) values(?)";
// 保存员工
String sql_emp = "INSERT INTO employee (empName,dept_id) VALUES (?,?)";
// 部门id
int deptId = 0;
try {
// 连接
con = JdbcUtil.getConnection();
/*****保存部门,获取自增长*******/
// 【一、需要指定返回自增长标记】
pstmt = con.prepareStatement(sql_dept,Statement.RETURN_GENERATED_KEYS);
// 设置参数
pstmt.setString(1, emp.getDept().getDeptName());
// 执行
pstmt.executeUpdate();
// 【二、获取上面保存的部门子增长的主键】
rs = pstmt.getGeneratedKeys();
// 得到返回的自增长字段
if (rs.next()) {
deptId = rs.getInt(1);
}
/*****保存员工*********/
pstmt = con.prepareStatement(sql_emp);
// 设置参数
pstmt.setString(1, emp.getEmpName());
pstmt.setInt(2, deptId);
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeAll(con, pstmt, rs);
}
}