10.JDBC操作Mysql数据库

本文深入解析JDBC的原理和应用,涵盖数据库连接、SQL执行、批处理、事务管理及ORM映射等内容,适合Java开发者学习数据库交互技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MySQL和Navicat安装和使用就不再介绍了

0.概念

JDBC(Java DataBase Connectivity,java数据库连接)为java开发者使用数据库提供了统一的编程接口。由一组java类和接口组成,是java程序与数据库系统通信的标准API。JDBC API使得开发人员可以使用纯java的方式连接使用数据库。

sun公司提供一套API,数据库厂商自己实现JDBC这套接口。数据库厂商的JDBC实现,我们就称他为此数据库的数据库驱动。

1.连接数据库

Driver接口:由数据库厂家提供,只需要食用即可
    装载MySQL驱动:Class.forName("com.mysql.jdbc.Driver");
    装载Oracle驱动:Class.forName("oracle.jdbc.driver.OracleDriver");
DriverManager接口:JDBC管理层,作用于用户和驱动程序之间 跟踪可用的驱动程序,并在数据库和驱动程序间建立连接
Connection接口:与特定数据库连接,在连接上下文中执行SQL语句并返回结果
    连接MySQL数据库:Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc?useSSL=false","user", "password");
    连接Oracle数据库:Connection connection = DriverManager.getConnection("jdbc:oracle:thin: @host:port:database",
"user", "password");

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * 测试数据库连接
 * @author chen
 *
 */
public class Demo01 {
	public static void main(String[] args) {
		Connection connection = null;
		try {
			//加载驱动类
			Class.forName("com.mysql.jdbc.Driver");
			//建立连接(连接对象内部其实包含了Socket对象,是一个远程连接比较耗时)
			//真正开发中,为了提高效率都会使用连接池管理连接对象
			connection = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/testjdbc","root", "123456");
			System.out.println(connection);
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			//释放资源
			if(connection!=null) {
				try {
					connection.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

打印对象的时候可能出现 Establishing SSL connection without server's identity verification is not recommended.警告

提示警告不建议使用没有带服务器身份验证的SSL连接,是在MYSQL5.5.45+, 5.6.26+ and 5.7.6+高版本中才有的这个问题。解决办法在警告中已经说明了:

1.在数据库连接的url中添加useSSL=false;
2.url中添加useSSL=true,并且提供服务器的验证证书
如果只是做一个测试的话,没必要搞证书那么麻烦啦,在连接后添加一个useSSL=false即可,例如:

jdbc:mysql://localhost:3306/test?useSSL=false

2.操作数据库

Statement接口:用于执行静态SQL语句并返回它生成结果的对象
三种Statement类:
    Statement: 由createStatement创建,用于发送简单的SQL语句(不含参数的)
    PreparedStatement:继承自Statement接口,由prepareStatement创建,用于发送含有一个或多个的输入参数的sql语句。                                              比Statement对象效率更高,并且可以防止SQL注入。(一般用它)
    CallableStatement:继承自PreparedStatement。由方法prePareCall创建,用于调用存储过程
常用Statement方法:
    excute()      运行语句,返回是否有结果集
    excuteQuery() 运行select语句,返回ResultSet结果集
    excuteUpdate()运行insert/update/delete操作,返回更新的行数

Statement类   

处理参数不方便,且易发生SQL注入  (后面注意释放Statement资源)

Statement stmt = connection.createStatement();
String name = "陈一";  
String sql = "insert into t_user(name,password,regTime) values('"+name+"',111111,now())";
//1.处理参数很不方便
//2.容易发生SQL注入   
// String id = "5 or 1=1";
//sql = "delete from t_user where id="+id;  SQL注入  会把所有记录删除
stmt.execute(sql);

 PrepareStatement类 

设置参数方便  且不易发生sql注入(注意释放PreparedStatement资源)

String sql = "insert into t_user(name,password,regTime) values(?,?,?)";  //占位符
PreparedStatement ps = connection.prepareStatement(sql);
//ps.setString(1, "陈二");  //1表示索引  因为是name是字符串setString
//ps.setString(2, "123444");//如果是int 可以是setInt() 等
//ps.setDate(3, new java.sql.Date(System.currentTimeMillis()));
			
//也可以都用setObject
ps.setObject(1, "陈三");
ps.setObject(2, "123444");
ps.setObject(3, new java.sql.Date(System.currentTimeMillis()));
			
ps.execute();

demo excuteQuery() excuteUpdate()以及ResultSet接口

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 测试ResultSet
 * @author chen
 *
 */
public class Demo04 {
	public static void main(String[] args) {
		Connection connection = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			connection = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/testjdbc?useSSL=false","root", "123456");
			
			String sql = "select id,name,password from t_user where id>?";
			ps = connection.prepareStatement(sql);
			ps.setObject(1, 2); //把id>2的都取出来
			rs = ps.executeQuery();
			while(rs.next()) {
				System.out.println(rs.getInt(1)+"--"+rs.getString(2)+"--"+rs.getString(3));
			}
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			if(rs!=null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if(ps!=null) {
				try {
					ps.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if(connection!=null) {
				try {
					connection.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

批处理(Batch)

由于PreparedStatement以便于空间比较小,所以进行批处理时使用Statement类

connection.setAutoCommit(false);  //事务设为手动提交
stmt = connection.createStatement();
for(int i=0;i<20000;i++) {  //插入20000条数据
	stmt.addBatch("insert into t_user(name,password,regTime)values('chen"+i+"',123123,now())");
	}
stmt.executeBatch();
connection.commit();  //手动提交

事务

一组要么同时执行成功,要么同时执行失败的SQL语句。是数据库操作的一个基本单元
事务开始于:

  •     连接到数据库上,并执行了一条DML语句(INSERT/UPDATE/DELETE)
  •     前一个事务结束后,又输入了另一条DML语句

事务结束于:

  •     执行COMMIT或ROLLBACK语句
  •     执行一条DDL语句,例如CREATE TABLE语句;这时会自动执行COMMIT语句
  •     执行一条DCL语句,例如GRANT语句;这时会自动执行COMMIT语句
  •     断开与数据库的连接
  •     执行一条FML语句,费语句却失败了;这时会为这个无效的DML语句执行ROLLBACK语句

四大特性(ACID特性)
原子性(Atomicity):事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
一致性(Consistency):一个事务内有一个操作失败时,所有更改的数据必须回滚到修改前的状态
隔离性(Isolation):由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状态,要么是
                 另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
                事务隔离级别从低到高 读取未提交 读取已提交 可重复读  序列化      
持久性(Durability):事务完成之后,它对于系统的影响是永久性的。

时间处理

java.sql.Date(年月日)     java.sql.Time(时分秒)   java.sql.Timestamp(年月日时分秒)都是java.util.Date的子类

java.sql.Date date = new java.sql.Date(System.currentTimeMillis());
ps.setObject(3, date);
Timestamp stamp = new Timestamp(System.currentTimeMillis());
//如果需要指定时间,可以使用Calendar类或者DataFormat类
//DateFormat format = new SimpleDateFormat(yyyy-MM-dd hh:mm:ss)
//Timestamp stamp = new Timestamp(format.parse("2015-10-1 10:11:12").getTime());
ps.setObject(4, stamp);

CLOB和BLOB

CLOB(Character Large Object)文本大对象
    用于存储大量的文本数据
    通常是以流的方式来进行处理,而非一般字段,一次即可读出数据
Mysql中相关类型
    TINYTEXT最大长度为255(2^8-1)字符的TEXT列
    TEXT最大长度为65,535(2^16-1)字符的TEXT列
    MEDIUMTEXT最大长度为16,777,215(2^24-1)字符的TEXT列
    LONGTEXT最大长度为4,294,967,295或4GB(2^32-1)字符的TEXT列
BLOB(Binary Large Object)
    用于存储大量的二进制数据
    通常是以流的方式来进行处理,而非一般字段,一次即可读出数据
Mysql中相关类型
    TINYBLOB最大长度为255(2^8-1)字节的BLOB列
    BLOB最大长度为65,535(2^16-1)字节的BLOB列
    TINYBLOB最大长度为16,777,215(2^24-1)字节的BLOB列
    TINYBLOB最大长度为4,294,967,295或4GB(2^32-1)字节的BLOB列

demo:  clob(blob同理,只不过是换成了字节流)

//数据库中插入文本数据
String sql = "insert into t_user(name,info) values(?,?)";
ps = connection.prepareStatement(sql);
ps.setString(1, "陈三");
ps.setClob(2, new FileReader(new File("d:/1.txt")));
ps.executeUpdate();
//数据库中取出文本数据
String sql = "select info from t_user where name=?";
ps = connection.prepareStatement(sql);
ps.setObject(1, "陈三");
rs = ps.executeQuery();
while(rs.next()) {
    Clob c = rs.getClob("info");
	br = new BufferedReader(c.getCharacterStream());(br的声明和关流就没显示了)
	String str = null;
	while((str=br.readLine())!=null) {
		System.out.println(str);
	}
}

ORM基本思想

英文Object Relational Mapping,对象关系映射,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

表结构跟类对应;表中字段和类的属性对应;表中记录和对象对应;
让javabean的属性名和类型尽量和数据库保持一致
一条记录对应一个对象。将这些查询到的对象放到容器中(List,Set,Map)

 将表中的数据进行封装的方式

将表中的一条记录封装到Object数组

/**
 * 使用Object[]封装一条记录
 * 使用List<Object[]>存储多条记录
 */
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class Demo {
	public static void main(String[] args) {
		Connection connection = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		//下面查询出两条记录,所以用Object[]封装一条记录,再放入容器中
		List<Object[]> list = new ArrayList<Object[]>(); 
		try {
			connection = JDBCUtils.getConnection();  //自己简单的封装了一下
			String sql = "select name,age,salary from employee where id>?";
			ps = connection.prepareStatement(sql);
			ps.setObject(1,1);  //查询id>1的
			rs = ps.executeQuery();
			while(rs.next()) {
				//用Object[]封装一条记录
				Object[] objs = new Object[3];
				objs[0] = rs.getObject("name");
				objs[1] = rs.getObject("age");
				objs[2] = rs.getObject("salary");
				
				//封装好后放入容器中
				list.add(objs);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			JDBCUtils.close(rs, ps, connection); //这也是简单封装了下
		}
		
		//关闭连接后仍然可以操作数据
		for(Object[] obj:list) {
			System.out.println(obj[0]+" "+obj[1]+"  "+obj[2]);			
		}
	}
}

将表中的一条记录封装到map

//之前部分一样
while(rs.next()) {
//用map封装一条记录
map = new HashMap<String,Object>();
map.put("name", rs.getObject(1));
map.put("age", rs.getObject(2));
map.put("salary", rs.getObject(3));
//封装好后放入容器中
list.add(map);  //上面声明过了List<Map<String,Object>> list = new ArrayList<Map<String,Object>>(); 
}

//操作数据
for(Map<String,Object> temp:list) {
	for(String key:temp.keySet()) {
		System.out.print(key+temp.get(key));
	}
	System.out.println("");
}

将表中的一条记录封装到javabean

Employee类

public class Employee { //表结构和类对应
	//表字段和类属性对应
	private Integer id;
	private String name;
	private Integer age;
	private double salary;
	private Integer departmentid;
	
	//构造器
	public Employee() {
		
	}
	public Employee(Integer id, String name, Integer age, double salary, Integer departmentid) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
		this.salary = salary;
		this.departmentid = departmentid;
	}
	
	//set、get方法
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public Integer getDepartmentid() {
		return departmentid;
	}
	public void setDepartmentid(Integer departmentid) {
		this.departmentid = departmentid;
	}

}
//上面部分一样
while(rs.next()) {
//用javabean封装一条记录
Employee emp = new Employee();
emp.setName(rs.getString(1));
emp.setAge(rs.getInt(2));
emp.setSalary(rs.getDouble(3));
				
list.add(emp);
}

//操作数据
for(Employee emp:list) {
    System.out.println(emp.getName()+" "+emp.getAge()+" "+emp.getSalary());
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值