1.全称:jdbc: java database connectivity 直译:java 数据库连接
2.表面意思:java连接并操作数据库 -- 解释jdbc是干什么的
3.本质含义:jdbc是sun公司制定的一套连接关系型数据库需要遵循的规范,即接口。而各个关系型数据库厂商自己来实现这个接口。程序员只需要面向接口编程。 -- 解释jdbc如何实现 连接并操作数据库 的
即:jdbc通过定义了一些接口,借助接口中定义的抽象方法,来规定java要如何连接数据库,如何操作数据库。
而接口中的抽象方法的具体实现,会因为数据库的不同实现方式也不一样,但是这个不是我们关心的,因为这些实现类是数据库厂商提供的,我们只需会调用接口中的方法就可以了。
所以:我们今天学习的内容并不是研究java到底如何连上数据库服务器的,这些底层也不是我们研究的范围,我们要学的就是一套操作步骤,学习在什么时候调用什么接口中的什么方法。
//1.导入jar包
//2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//3.创建连接
Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","root");
System.out.println(con);
//4.定义sql
String sql="update account set balance=balance+500 where id=1";
//5.获取执行sql的对象 stmt
Statement stmt = con.createStatement();
//6.执行sql
int count = stmt.executeUpdate(sql);
//7.结果处理
System.out.println(count);
//8.释放资源
stmt.close();
con.close();
1.得到了连接对象con,即意味着java程序和数据库服务器已经连通了。
2.stmt对象看似是执行sql,其实是发送sql给数据库服务器去执行
1. 导入jar包
2. 加载驱动
3. 构建连接对象
4. 生成statement对象
5. 执行sql
6. 处理结果
7. 释放资源
两个功能
获取连接对象的方法
//1.通过 连接协议,用户名,密码 得到数据库连接对象
Connection getConnection(String url,String user,String password)
//2.通过 url,Properties 对象得到连接对象
Connection getConnection(String url,Properties p)
连接数据库四大参数
1.驱动类的字符串名:com.mysq.jdbc.Driver -- 在jar文件的META-INF/services文件夹下
2.连接协议路径字符串url:不同的数据库url是不同的,mysql的写法
jdbc:mysql://localhost:3306/数据库名[?参数名=参数值]
3.数据库用户名 :root
4.数据库登录密码:root
url 是什么?
是一个连接数据库的路径,用于标识数据库的位置
包含:jdbc协议,mysql子协议,数据库所在主机名,数据库服务器的端口号,数据库名
如果是本地服务器,端口号是3306,可简写:
jdbc:mysql:///数据库名
乱码处理
如果使用jdbc对数据库进行操作时出现中文乱码,可以在url后指定字符集编码参数,表示让数据库以UTF-8编码来处理数据
jdbc:mysql:///数据库?characterEncoding=utf8
mysql8还需要指定时区
jdbc:mysql:///数据库名?useSSL=false&serverTimezone=UTC&characterEncoding=utf8
案例
//1.使用用户名,密码,url得到连接对象
public static void main(String [] args){
String url="jdbc:mysql:///db1";
Connection con=DriverManager.getConnection(url,"root","root");
System.out.println(con);
}
//2.使用properties对象和url得到连接对象
public static void main(String [] args){
String url="jdbc:mysql:///db1";
//将用户名和密码存进Properties对象中
Properties info=new Properties();
info.setProperty("user","root");
info.setProperty("password","root");
//使用url和Properties对象得到连接对象
Connection con=DriverManager.getConnection(url,info);
System.out.println(con);
}
//3.使用properties文件和url得到连接对象
@Test
public void test1(){
try {
//注册驱动 Driver
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接数据库对象 DriverManager
String url="jdbc:mysql://localhost:3306/db3 ?useSSL=false&serverTimezone=UTC";
Connection con = DriverManager.getConnection(url, "root", "123456");
System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void test2(){
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/db3 ?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";
Properties p = new Properties();
p.setProperty("user","root");
p.setProperty("password","123456");
Connection con = DriverManager.getConnection(url,p);
System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void test3(){
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/db3 ?useSSL=false&serverTimezone=UTC";
InputStream is = Hello1.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties p = new Properties();
p.load(is);
Connection con = DriverManager.getConnection(url, p);
System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
Connection是一个接口,具体的实现类由数据库厂商提供实现,代表一个连接对象
功能:
Statement createStatement()
PreparedStatement prepareStatement(String sql) //预编译对象,效率更高
- 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
- 提交事务:commit()
- 回滚事务:rollback()
功能:用于发送sql语句给服务器,用于执行静态sql语句并返回结果
方法
//用于发送dml语句,执行增删改的操作,返回对数据库影响的行数,还可以执行ddl语句
int executeUpdate(String sql)
//用于发送dql语句,执行查询的操作,返回结果集对象
ResultSet executeQuery(String sql)
public class Hello2 {
private Connection con;
@Before //执行@Test前,先执行@Before
public void init(){
try {
//注册驱动 Driver
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接数据库对象 DriverManager
String url="jdbc:mysql://localhost:3306/db4 ?useSSL=false&serverTimezone=UTC";
con = DriverManager.getConnection(url, "root", "123456");
// System.out.println(con);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test//dml 新增
public void test1(){
try {
String sql="insert into dept values(50,'信息部','武汉')";
Statement state = con.createStatement();
// PreparedStatement ps = con.prepareStatement("insert into dept values(60,'信息部','武汉')");
int i=state.executeUpdate(sql);
System.out.println(i);//返回表格影响的行数 1
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test//dml 删除
public void test2(){
try {
String sql="delete from dept where id='50'";
Statement state = con.createStatement();
int i=state.executeUpdate(sql);
System.out.println(i);//返回表格影响的行数 1
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test//dml 修改
public void test3(){
try {
String sql="update dept set loc='武汉' where id='40'";
Statement state = con.createStatement();
int i=state.executeUpdate(sql);
System.out.println(i);//返回表格影响的行数 1
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test//ddl 修改表名
public void test4(){
try {
String sql="alter table dept rename to dept1";
Statement state = con.createStatement();
int i=state.executeUpdate(sql);
System.out.println(i);// 返回0
} catch (SQLException e) {
e.printStackTrace();
}
}
}
注意:
1.需要释放的对象 ResultSet Statement Connection
2.释放原则:先开的后关,后开的先关 ResultSet --> Statement --> Connection
3.放在finally代码块中
finally {
//6. 释放资源
//关闭之前要先判断
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
作用:封装数据库查询的结果集,并提供了遍历结果集的方法,取出每一条记录
方法
boolean next() -- 每调用一次,行光标向下移动1行,返回true表示还有下一条记录,否则返回false
数据类型 getXxx() 可以通过列名或列号获取某一行的某一列的数据
演示
代码演示–查询员工表,并封装结果集到list集合中
/**
* 查询所有emp对象
* @return
*/
public List<Emp> findAll(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Emp> list = null;
try {
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
//3.定义sql
String sql = "select * from emp";
//4.获取执行sql的对象
stmt = conn.createStatement();
//5.执行sql
rs = stmt.executeQuery(sql);
//6.遍历结果集,封装对象,装载集合
Emp emp = null;
list = new ArrayList<Emp>();
while(rs.next()){
//获取数据
int id = rs.getInt("id");
String ename = rs.getString("ename");
int job_id = rs.getInt("job_id");
int mgr = rs.getInt("mgr");
Date joindate = rs.getDate("joindate");
double salary = rs.getDouble("salary");
double bonus = rs.getDouble("bonus");
int dept_id = rs.getInt("dept_id");
// 创建emp对象,并赋值
emp = new Emp();
emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job_id);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDept_id(dept_id);
//装载集合
list.add(emp);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
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();
}
}
}
return list;
}
注意事项
核心步骤:
1.为什么要写工具类?
工具类的作用:
1.实现注册驱动 和 连接对象的获取
2.释放资源
代码演示
/**
* JDBC工具类
*/
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
/**
* 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
*/
static{
//读取资源文件,获取值。
try {
//1. 创建Properties集合类。
Properties pro = new Properties();
//获取src路径下的文件的方式--->ClassLoader 类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
// System.out.println(path);///D:/IdeaProjects/itcast/out/production/day04_jdbc/jdbc.properties
//2. 加载文件
// pro.load(new FileReader("D:\\IdeaProjects\\itcast\\day04_jdbc\\src\\jdbc.properties"));
pro.load(new FileReader(path));
//3. 获取数据,赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4. 注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return 连接对象
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
/**
* 释放资源
* @param stmt
* @param conn
*/
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);//直接调用重载的close方法
}
/**
* 释放资源
* @param stmt
* @param conn
*/
public static void close(ResultSet rs,Statement stmt, Connection conn){
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();
}
}
}
}
注意事项
可能出现的异常
代码演示
/**
* 登录方法
*/
public boolean login(String username ,String password){
if(username == null || password == null){
return false;
}
//连接数据库判断是否登录成功
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
//1.获取连接
try {
conn = JDBCUtils.getConnection();
//2.定义sql 获取username 和password两个数据
String sql = "select * from user where username = '"+username+"' and password = '"+password+"' ";
System.out.println(sql);
//3.获取执行sql的对象
stmt = conn.createStatement();
//4.执行查询
rs = stmt.executeQuery(sql);
return rs.next();//如果有下一行,则返回true
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs,stmt,conn);
}
return false;
}
注意事项
可能出现的异常
代码演示
/**
* 登录方法,使用PreparedStatement实现
*/
public boolean login2(String username ,String password){
if(username == null || password == null){
return false;
}
//连接数据库判断是否登录成功
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
//1.获取连接
try {
conn = JDBCUtils.getConnection();
//2.定义sql
String sql = "select * from user where username = ? and password = ?";
//3.获取执行sql的对象
pstmt = conn.prepareStatement(sql);
//给?赋值
pstmt.setString(1,username);
pstmt.setString(2,password);
//4.执行查询,不需要传递sql
rs = pstmt.executeQuery();
//5.判断
return rs.next();//如果有下一行,则返回true
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs,pstmt,conn);
}
return false;
}
注意事项
可能出现的异常
两种实现方式的差异:
1.sql语句不再是拼接参数 ,使用?代替参数
2.在创建stmt对象时,空参 ; 在创建pstm对象时,传入sql模板 --预编译
3.pstm对象还需要为?填充参数值
4.stmt对象执行sql时,需要传入sql ; pstm对象执行sql时,不用再传sql
优点:
1.PreparedStatement对象可以防止sql注入,Statement对象不可以
2.PreparedStatement对象是预编译方式执行sql,会提前检查sql是否有语法错误,因此执行效率更高
1.开启 con.setAutoCommit(false); 放在con对象创建后
2.回滚 con.rollback(); 放在catch代码块
3.提交 con.commit(); try的最后一行
代码演示
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
//1.获取连接
conn = JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//2.定义sql
//2.1 张三 - 500
String sql1 = "update account set balance = balance - ? where id = ?";
//2.2 李四 + 500
String sql2 = "update account set balance = balance + ? where id = ?";
//3.获取执行sql对象
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
//4. 设置参数
pstmt1.setDouble(1,500);
pstmt1.setInt(2,1);
pstmt2.setDouble(1,500);
pstmt2.setInt(2,2);
//5.执行sql
pstmt1.executeUpdate();
// 手动制造异常
int i = 3/0;
pstmt2.executeUpdate();
//提交事务
conn.commit();
} catch (Exception e) {
//事务回滚
try {
if(conn != null) {
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JDBCUtils.close(pstmt1,conn);
JDBCUtils.close(pstmt2,null);
}
}
注意事项
可能出现的异常
对一个表进行简单的增删改查
查询一个表中所有的数据,得到一个结果集,并在控制台全部输出
查询一个表中所有的数据,得到一个结果集,封装结果集到list集合,并在控制台输出
工具类的编写–读取外部的properties配置文件:1.获取连接对象 2.释放资源
用statement去实现登录案例
用子接口preparedstatement去优化登录案例
事务–转账案例
在控制台实现一个百里半用户管理系统,包含3个功能:
1.用户登录 2.注册 3.用户查询。
启动程序后,进入主菜单选项:
输出:“请选择您要操作的功能:1.用户登录 2.新用户注册 3所有用户查询: ”
功能说明:
1.用户登录:
请用户输入用户名和密码,接收后,去数据库的users表中查询是否存在该用户名。并输出合理的提示,例如:登录成功! 用户名不存在! 密码错误!
不论登录是否成功,都返回主菜单界面。
2.新用户注册 :
请用户输入用户名和密码,接收后,去数据库的users表中执行新增操作。并输出合理的提示,例如:注册成功! 用户名已存在!
3.所有用户查询:
该功能必须在用户登录后方可查看,如果用户已经登录成功,即可在控制台查看所有用户的所有信息。如果没有登录,提示:您还没有登录呢,无权查看用户信息!
说明:
users表中只需要3列即可,id,name,password.