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());
}