前言
调用数据库需要下载对应数据库的驱动
建议把参数写到properties中
JDBC编程六大步骤
1.注册驱动(连接对应品牌的数据库)
2.获取连接(表示JVM的进程和数据库进程之间的通道打开,使用完后一定要关闭)
3.获取数据库操作对象(专门执行sql语句的对象)
4.执行sql语句(DQL,DML…)
5.处理查询结果集(只有当第四步执行的是select语句时才有这一步)
6.释放资源(使用完资源之后一定要关闭资源)
1.注册驱动
DriverManager类的registerDriver(Driver driver)注册所需驱动
Driver driver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver(driver);
常用方式
Class.forName(“com.mysql.cj.jdbc.Driver”);加载这个类来运行静态代码块实现驱动的注册
常用原因:参数是一个字符串,字符串可以写到properties中
2.获取连接
DriverManager类的getConnection(String url, String root, String password)获取到与数据库连接的Connection类
Connection con = null;
con=DriverManager.getConnection("jdbc:mysql://localhost:3306/spj?useSSL=false&serverTimezone=UTC","root","25666524qq");
3.创建可执行sql语句的对象
通过连接connection对象的creatStatement()创建可执行sql语句对象
存在问题:1.存在SQL注入问题 2.存在拼串操作,较为繁琐
Statement statement = null;
statement=con.createStatement();//创建对象
PreparedStatement类
//预编译sql语句,返回PrepareStatement实例
String sql = "update s set STATUS=? where CITY=?";
statement = conn.prepareStatement(sql);
//填充占位符
statement.setObject(1, 10);
statement.setObject(2,"顺德");
//执行
statement.execute();
与Statement相比的好处:
1.解决了拼接字符串的繁琐操作,使用了占位符
2.解决了SQL注入问题,使用了预编译
3.由于使用占位符,所以PreparedStatement可操作Blob数据
4.提高了批处理的效率
1.处理Blob数据
上传
用FileInputStream载入图片,再通过PreparedStatement的setBlob(int index, InputStream is);来设置占位符
下载
通过查询获取的结果集ResultSet,用InputStream来接收ResultSet的getBinaryStream()从而得到输入流,再通过OutputStream输出流来输出就可得到Blob数据即图片等非文本资源
2.批处理
在获取连接设置url时要加入rewriteBatchedStatements = true,开启数据库的批处理
其次关闭连接的自动提交即setAutocommit (false)
然后通过addBatch()添加命令
添加到一定程度后executeBatch()执行批处理
然后clearBatch()清空为了接收下一批任务
最后全部完成了才提交即Connection的commit()
4.执行sql语句
使用String sql=" …"传递sql语句到数据库并执行返回结果
jdbc中的sql语句不能有分号
statement对象中executeUpdate(sql)专门执行DML语句(insert delete update) 返回值为受影响的数据库中记录条数
插入
insert into …
删除
delete
更新
update
-------
statement对象中executeQuery(sql)专门执行DQL语句(select)返回值为查询结果集
查询
select
5.处理查询结果集
getString()方法的特点是:不管数据库中数据类型是什么,都以String形式返回;下标都是从1开始
getString(String Label_Name)通过列名称获取数据,不是表中列名称是查询结果集的列名称
还有getInt()、getDouble()
ResultSetMetaData rsmd = set.getMetaData();
通过ResultSetMetaData 获取元数据来获取列数
通过反射给对象赋值
ResultSetMetaData rsmd = set.getMetaData();
while(set.next()){
Factory factory = new Factory();
for(int i=0;i<rsmd.getColumnCount();i++){
Object colValue = set.getObject(i+1);
try {
Field field = Factory.class.getDeclaredField(rsmd.getColumnLabel(i+1));
field.setAccessible(true);
field.set(factory,colValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
System.out.println(factory);
}
6.释放资源
先释放ResultSet再释放statement最后释放connection
7.使用ResourceBundle类调用propreties文件(重点)
使用ResourceBundle类的getBundle(String basename)来实现调用,通过getString(String key)来获取所需数据
8.代码
public void JDBCTest(){
Connection con = null;
Statement statement = null;
ResultSet set = null;
try {
//获取属性值
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("Driver_Name");
String url = bundle.getString("url");
String user = bundle.getString("user");
String password = bundle.getString("password");
//1.注册驱动(反射)
Class.forName(driver);
//2.获取连接
con = DriverManager.getConnection(url, user, password);
//3.创建可执行sql语句对象(statement)
statement = con.createStatement();
//4.执行sql语句
String sql = "select * from s";
set = statement.executeQuery(sql);
//5.处理查询结果集
while(set.next()){
System.out.println(set.getString(1)+"|"+set.getString(2)+"|"+set.getString(3)+"|"+set.getString(4));
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}finally {//6.关闭资源(先关statement再关connection)
if(set!=null){
try {
set.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
9.封装性
使用类的静态方法返回连接connection
使用方法关闭资源public void closeResource(Connection conn, Statement statement)
10.ORM封装思想
ORM: object relational mapping
一个数据表对应一个java类
表中的一条记录对应java类的一个对象
表中的一个字段对应java类的一个属性
public class Factory{
private String SNO;
private String SNAME;
private String STATUS;
private String CITY;
public Factory() {
super();
}
public Factory(String SNO, String SNAME, String STATUS, String CITY) {
this.SNO = SNO;
this.SNAME = SNAME;
this.STATUS = STATUS;
this.CITY = CITY;
}
public String getSNO() {
return SNO;
}
public void setSNO(String SNO) {
this.SNO = SNO;
}
public String getSNAME() {
return SNAME;
}
public void setSNAME(String SNAME) {
this.SNAME = SNAME;
}
public String getSTATUS() {
return STATUS;
}
public void setSTATUS(String STATUS) {
this.STATUS = STATUS;
}
public String getCITY() {
return CITY;
}
public void setCITY(String CITY) {
this.CITY = CITY;
}
@Override
public String toString() {
return "Factory{" +
"SNO='" + SNO + '\'' +
", SNAME='" + SNAME + '\'' +
", STATUS='" + STATUS + '\'' +
", CITY='" + CITY + '\'' +
'}';
}
}
set = statement.executeQuery();
while(set.next()){
String sno = set.getString(1);
String sname = set.getString(2);
String status = set.getString(3);
String city = set.getString(4);
Factory factory = new Factory(sno, sname, status, city);
System.out.println(factory);
}
11.事务
**事务:**一组逻辑操作单元使数据从一种状态变换到另一种状态
**事务处理:**保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式,当在一个事务中执行多个操作时,要么所有的事务都被提交commit;要么放弃所有的修改,整个事务回滚rollback到上一次提交的状态。
哪些操作会导致自动提交
1.DDL(creat\alter\drop)(无法通过setAutocommit = false来取消)
2.DML 可通过设置setAutocommit = false来取消自动提交
3.关闭连接
为了避免自动提交,一般处理事务的连接由外部自行提供、关闭
由于考虑到数据库连接池,需要先将连接状态设置为默认即自动提交打开,再关闭连接
ACID属性
1.原子性
事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
2.一致性
事务必须使数据库从一个一致性状态变换到另一个一致性状态
3.隔离性
一个事务的执行不能被其他事务干扰
4.持久性
一个事务一旦被提交,它对数据库中的改变都是永久的
并发问题:
脏读:两个事务A、B,A读取了已经被B更新但还没被提交的字段,若B回滚,A读取的内容就是临时且无效的;
不可重复读:对于两个事务A、B,A读取一个字段然后B更新了该字段,然后A再次读取同一字段值就不同了
幻读:对于两个事务A、B,A从一个表中读取一个字段,然后B在该表中插入一些新的行,之后,A再次读取同一个表就会多出几行
四种隔离级别
1.读取未提交数据
2.读取已提交事务
3.可重复读(锁操作行)
4.串行化(锁操作表)
12.连接池Druid
1.导jar包
2.设置properties配置文件
3.读取properties获取所需参数
4.通过DruidDataSourceFactory.createDataSource(properties)创建DruidDataSource类
5.通过getConnection()获取一个连接,最后将连接参数调为默认后close()
13.(commons-dbutils)开源的JDBC工具类库
使用QueryRunner类
关于不同的返回结果使用的handler:MapHandler、MapListHandler、BeanHandler
特殊值的需求如最大值或个数:ScalarHandler
自定义handler:ResultSetHandler<>{}
关闭资源
使用dbutils.jar包中的DbUtils.close(…)比如connection、Statement、ResultSet