1.加载驱动器、2.创建connection对象、3.创建Statement对象、4.Statement(executeQuery方法)执行sql语句、5.创建处理结果集对象ResultSet、6.处理异常,关闭所有JDBC对象资源(注意关闭顺序与声明顺序相反,先关结果集对象、后关statement对象、最后关connection对象)。
首先准备JDBC所需的四个参数(user,password,url,driverClass)
(1)user用户名
(2)password密码
(3)URL定义了连接数据库时的协议、子协议、数据源标识,它们之间用冒号隔开。 书写形式: 协议:子协议:数据源标识
例如:(MySql的连接URL)
jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8 ;
解释:"jdbc(这是协议以jdbc开头):mysql(这是子协议,数据库管理系统称)://localhost(数据库来源地址):3306(目标端口)/test(要查询的表)?",而"useUnicode=true&characterEncoding=UTF8";添加这个是为了防止乱码,指定使用Unicode字符集 ,且使用UTF-8来编辑。
(4)driverClass连接数据库所需的驱动。
(5)JDBC的url实现负载均衡,多节点部署数据库的url拼写方式:
dbc:oracle:thin:@
(description=(TRANSPORT_CONNECT_TIMEOUT=1)
(address_list=(load_balance=off)(failover=on)
(address=(protocol=tcp)(host=RAC1-vip)(port=1521))
(address=(protocol=tcp)(host=RAC2-vip)(port=1521))
(address=(protocol=tcp)(host=RAC3-vip)(port=1521)))
(connect_data=(service_name=orcl)(failover_mode=(type=select)(method=basic)))
)
解释:LOAD_BALANCE=OFF,客户端进程首先会尝试连接RAC1-vip,如果连不上,则会尝试RAC2-vip,如果再连不上就尝试RAC3-vip。如果设置为ON则会随机的选择一个做均衡负载。LOAD_BALANCE=on负载均衡,FAILOVER = on 失败自动切换,这两个参数是搭配在一起的。
在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),有三种方法,此处通过java.lang.Class类的静态方法forName(String className)实现。成功加载后,会将Driver类的实例注册到DriverManager类中。
try{//加载MySql的驱动类
Class.forName("com.mysql.jdbc.Driver") ;
}catch(ClassNotFoundException e){
System.out.println("找不到驱动程序类 ,加载驱动失败!");
e.printStackTrace() ;
}
//连接MySql数据库,用户名和密码都是root
String url = "jdbc:mysql://localhost:3306/test" ;
String username = "root" ;
String password = "root" ;
try{
Connection con = DriverManager.getConnection(url , username , password ) ;
}catch(SQLException se){
System.out.println("数据库连接失败!");
se.printStackTrace() ;
}
要执行SQL语句,必须先获得java.sql.Statement实例。
//Connection接口下的方法:Statement createStatement()
Statement stmt=conn.createStatement();
PreparedStatement pstmt = conn.PreparedStatement() ;
CallableStatement cstmt = conn.prepareCall("{CALL demoSp(? , ?)}") ;
1、statement每次执行sql语句,数据库都要执行sql语句的编译,而PreparedStatement可以使用占位符,预编译处理大量相似sql语句,比Statement效率高。
2、使用 Statement 对象。在对数据库只执行一次性存取时用 Statement 对象进行处理。因为PreparedStatement 对象的开销比Statement大,对于一次性操作并不会带来额外的好处。
3、执行许多SQL语句的JDBC程序产生大量的Statement和PreparedStatement对象。通常认为PreparedStatement对象比Statement对象更有效,特别是如果带有不同参数的同一SQL语句被多次执行的时候。PreparedStatement对象允许数据库预编译SQL语句,这样在随后的运行中可以节省时间并增加代码的可读性。
4、 PreparedStatement 减少编译次数。提高了安全性(阻止了SQL注入)
5、PreparedStatement 可以实现操作Blob类型、Clob类型的数据
详细见:(20条消息) preparedStatement和Statement区别_minose的博客-CSDN博客_preparedstatement和statement的区别
Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute
boolean flag = stmt.execute(String sql) ;----执行SQL语句,如果返回值是结果集则为true,否则为false
ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ;----执行SQL语句,返回值为ResultSet
int rows = stmt.executeUpdate("INSERT INTO ...") ;----执行SQL语句,返回值为所影响的行数
根据返回结果分为两种情况:
(1)执行更新返回的是本次操作影响到的记录数。
(2)执行查询返回的结果是一个ResultSet对象。
ResultSet接口下常见的方法:
beforeFirst()----将游标移动到ResultSet中第一条记录(的前面)
afterLast()----将游标移动到ResultSet中最后一条记录(的后面)
absolute(intcolumn)----将游标移动到相对于第一行的指定行,负数则为相对于最后一条记录
previous()----将游标上移一行
next()----将游标下移一行
ResultSet.TYPE_SCROLL_SENSITIVE----结果集可以滚动
ResultSet.CONCUR_READ_ONLY ----结果集只读,不能修改
While(rs.next()){
rs.getInt(columnIndex); //通过列的序号来获取字段的值
rs.getString(columnName);//通过列的名字来获取字段的值
}
操作完成以后要把所有JDBC对象全都关闭,以释放JDBC资源,关闭顺序和声明顺序相反:
if(rs !=null){ // 关闭结果集
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt !=null){ // 关闭statement声明
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn !=null){ // 关闭连接对象
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
基本原理;保存数据时,把需要保存的对象的属性值全部取出来再拼凑sql语句。查询时,将查询到的数据全部包装成一个java对象。
假设数据库名称为:mysql_test_jdbcinstance,里面有一个表userinfo。如图:
package com.test.workTest.JdbcClassInstance;
/**
* 1.数据库表对应的表的对象类
*/
public class UserInfo {
private int id;
private String name;
private String pwd;
private int age;
@Override
public String toString() {
return "UserInfo [id=" + id + ", name=" + name + ", pwd=" + pwd + ", age="
+ age + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.test.workTest.JdbcClassInstance;
import java.sql.Connection;
import java.sql.DriverManager;
/**
* 2.获得数据库连接的工厂类:
*/
public class ConnectDBFactory {
public static Connection getDBConnection() {
Connection conn = null;
try {
/**
* 你自己的数据库参数,详见本博客上面描述
*/
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/mysql_test_jdbcinstance";
String user = "root";
String password = "***";
conn = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
package com.test.workTest.JdbcClassInstance;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
* 3.操作数据库的dao类
*/
public class TableSqlDao {
/**
* 解析出保存对象的sql语句
* @param object:需要保存的对象
* @return:保存对象的sql语句
*/
public static String getSaveObjectSql(Object object) {
// 定义一个sql字符串
String sql = "insert into ";
// 得到对象的类
Class c = object.getClass();
// 得到对象中所有的方法
Method[] methods = c.getMethods();
// 得到对象中所有的属性
Field[] fields = c.getFields();
// 得到对象类的名字
String cName = c.getName();
// 从类的名字中解析出表名
String tableName = cName.substring(cName.lastIndexOf(".") + 1,
cName.length());
sql += tableName + "(";
List mList = new ArrayList();
List vList = new ArrayList();
for (Method method : methods) {
String mName = method.getName();
if (mName.startsWith("get") && !mName.startsWith("getClass")) {
String fieldName = mName.substring(3, mName.length());
mList.add(fieldName);
System.out.println("字段名字----->" + fieldName);
try {
Object value = method.invoke(object, null);
System.out.println("执行方法返回的值:" + value);
if (value instanceof String) {
vList.add("\"" + value + "\"");
System.out.println("字段值------>" + value);
} else {
vList.add(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
for (int i = 0; i < mList.size(); i++) {
if (i < mList.size() - 1) {
sql += mList.get(i) + ",";
} else {
sql += mList.get(i) + ") values(";
}
}
for (int i = 0; i < vList.size(); i++) {
if (i < vList.size() - 1) {
sql += vList.get(i) + ",";
} else {
sql += vList.get(i) + ")";
}
}
return sql;
}
public static List getDatasFromDB(String tableName, int Id) {
return null;
}
/**
* 将对象保存到数据库中
* @param object:需要保存的对象
* @return:方法执行的结果;1:表示成功,0:表示失败
*/
public int saveObject(Object object) {
Connection con = ConnectDBFactory.getDBConnection();
String sql = getSaveObjectSql(object);
PreparedStatement psmt = null;
try {
// Statement statement=(Statement) con.createStatement();
psmt = con.prepareStatement(sql);
psmt.executeUpdate();
return 1;
} catch (SQLException e) {
e.printStackTrace();
return 0;
} finally {
if(psmt !=null){ // 关闭statement声明
try {
psmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con !=null){ // 关闭连接对象
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 从数据库中取得对象
* @param:对象所属的类
* @param:对象的id
* @return:需要查找的对象
*/
public Object getObject(String className, int Id) throws SQLException {
// 得到表名字
String tableName = className.substring(className.lastIndexOf(".") + 1,
className.length());
// 根据类名来创建Class对象
Class c = null;
try {
c = Class.forName(className);
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
// 拼凑查询sql语句
String sql = "select * from " + tableName + " where Id=" + Id;
System.out.println("查找sql语句:" + sql);
// 获得数据库链接
Connection con = ConnectDBFactory.getDBConnection();
// 创建类的实例
Object obj = null;
Statement stm = null;
// 得到执行查寻语句返回的结果集
ResultSet set = null;
// 得到对象的方法数组
Method[] methods = null;
try {
stm = con.createStatement();
set = stm.executeQuery(sql);
methods = c.getMethods();
// 遍历结果集
while (set.next()) {
obj = c.newInstance();
// 遍历对象的方法
for (Method method : methods) {
String methodName = method.getName();
// 如果对象的方法以set开头
if (methodName.startsWith("set")) {
// 根据方法名字得到数据表格中字段的名字
String columnName = methodName.substring(3,
methodName.length());
// 得到方法的参数类型
Class[] parmts = method.getParameterTypes();
if (parmts[0] == String.class) {
// 如果参数为String类型,则从结果集中按照列名取得对应的值,并且执行改set方法
method.invoke(obj, set.getString(columnName));
}
if (parmts[0] == int.class) {
method.invoke(obj, set.getInt(columnName));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(set !=null){ // 关闭结果集
try {
set.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stm !=null){ // 关闭statement声明
try {
stm.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(con !=null){ // 关闭连接对象
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return obj;
}
}
package com.test.workTest.JdbcClassInstance;
import java.sql.SQLException;
/**
* 测试类
*/
public class SqlSpellTest {
public static void main(String args[]) throws SQLException {
//获得TableSqlDao对象
TableSqlDao session = new TableSqlDao();
//创建一个UserInfo对象
UserInfo user = new UserInfo();
//设置对象的属性
user.setId(1);//每次执行都需要改下ID,因为数据库ID字段唯一
user.setAge(24);
user.setPwd("123654");
user.setName("oneGoodMan");
//将对象保存到数据库中
int sql = session.saveObject(user);
System.out.println("保存对象的sql语句:" + sql);
//查找对象,这个形参className需要带上你自己pojo类的包地址
UserInfo userInfo = (UserInfo) session.getObject(
"com.test.workTest.JdbcClassInstance.UserInfo", 1);
System.out.println("获取到的信息:" + userInfo);
}
}