JDBC
Jdbc: java和数据库连接,提供了一种与平台无关的执行sql语句的api。方便实现多种关系型数据的统一操作。(java database connectivity)
Jdbc 分类:
jdbc本地驱动: 由数据库生产商提供的驱动包,进行驱动使用
jdbc网络驱动: 通过网络协议进行驱动,无网情况不能使用。
jdbc协议驱动: 把其它的驱动转化成协议。(dbms协议)
企业开发一般用本地驱动.
jdbc中常用的接口和类,ojdbc6.jar 这个包中,含了很多class,用于连接
在idea中的使用:
在项目结构中,找到库,然后加载进来ojdbc6.jar 这个包
JDBC连接数据库的操作
声明数据库驱动,数据源的url,用于登录数据库的账户和密码(将其他功能封装成方法的时候方便使用)
String driver = “数据库驱动名称”;
String url = “数据库连接地址”
String user = “用来连接数据库的用户名”;
String pwd = “用来连接数据库的密码”;
加载数据库驱动
Class.forName(driver);
根据url创建数据库连接对象Connection
Connection con = DriverManage.getConnection(url,user,pwd);
//先连上数据库,在操作
//Connection 数据库连接 名字自己取
public Connection getdb() throws ClassNotFoundException, SQLException {
//找到驱动类,加载数据库驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//DriverManager 用来管理驱动,针对已驱动的程序
//通过驱动管理 来建立连接 根据url创建数据库连接对象Connection
//第一个参数,用来指定数据库用的参数 哪种数据库 地址 端口
//用户名 密码
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "system", "sun");
return con;
}
java调用存储过程:
1.创建表和对应的序列
2.创建对应的存储过程
3.在java中调用
//创建表和对应的序列
create table u3(
id number(4) primary key,
name varchar2(20) not null,
pw varchar2(20) not null,
em varchar2(20) not null
);
create sequence seq_u3;
//创建对应的存储过程
create or replace procedure pro_7(id in number,
namea in varchar2,pw in varchar2,em in varchar2)
is
begin
insert into u3 values(id,namea,pw,em);
end;
在java的调用中,prepareCall是调用存储过程的意思,我们可以使用两种方式传值进去
//在java中调用
public static void pro_7(String namea,String pw,String em) throws ClassNotFoundException, SQLException {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe",
"system", "sun");
//连接上后
//调用存储过程,参数为一个字符串,只是字符串的内容是一个sql形式
//"+namea+" 因为外面已经有了“”
//调用整个存储过程,要交给预处理平台,准备执行事宜的平台
//?占用一个位子,表示此处等下要放入变量
//方式一:
CallableStatement cs = connection.prepareCall("{call pro_7(seq_u3.nextval,'"+namea+"','"+pw+"','"+em+"')}");
//方式二:
// CallableStatement cs = connection.prepareCall("{call pro_7(seq_u3.nextval,?,?,?)}");
// cs.setString(1,namea);
// cs.setString(2,pw);
// cs.setString(3,em);
cs.execute(); //预处理平台执行
connection.commit(); //事务提交
}
java进行dml和dql操作:
//声明数据库驱动,数据源的url,用于登录数据库的账户和密码(将其他功能封装成方法的时候方便使用)
⚪String driver = “数据库驱动名称”;
⚪String url = “数据库连接地址”
⚪String user = “用来连接数据库的用户名”;
⚪String pwd = “用来连接数据库的密码”;
//加载数据库驱动
⚪Class.forName(driver);
//根据url创建数据库连接对象Connection
⚪Connection con = DriverManager.getConnection(url,user,pwd);
//用数据库连接对象创建Statement对象(或PrepareStatement)
⚪Statement s = con.createStatement();
或
⚪PrepareStatement ps = con.PrepareStatement(sql);
//做数据库的增删改查工作
⚪ResultSet rs = s.executeQuery();
//关闭结果集对象Resultset,statement对象,connection对象,
rs.close();
s.close();
con.close();
DriverManager 是用来管理驱动程序,原理OracleDriver
类会有jdbc协议,进行驱动,驱动了后,才能连接数据库
Driver:每个驱动程序都应该提供一个实现Driver接口的类。里面有数据库通信
Connection:表示与数据库的连接,含很多与数据库的通信的方法。每次通信都是一次唯一的连接,要注意关闭.或提交。
数据库连接对象创建对象时,Statement是什么?PreparedStatement和Statement的区别?
Statement:接口,用来创建一个对象,可把字符串的sql语句 提交到数据库,来执行
①PreparedStatement是Statement的子类
②PreparedStatement能对sql语句进行预处理
③PreparedStatement效率更高
④Statement的对数据库操作方法是execute(),PreparedStatement的对数据库操作的方法是executeUpdate(),executeQuery(),execute()
execute():能执行查询,增删改查。返回类型是boolean
executeUpdate():能执行增删改,返回类型是int,返回值是受影响的行数
executeQuery():能执行查询,返回值是ResultSet。
ResultSet:通过executeQuery() 查询后的结果集,有比如 next等迭代的方法,取数据时,通过get 字段名来取。ResultSet对象保持一个光标指向其当前的数据行。
Demo:
下面展示新增、修改、删除数据
public class SuDemo {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
Stu s=new Stu();
s.setName("11");
s.setTel("22");
s.setAddr("33");
s.setId(2);
// int inserts = inserts(s);
// int update = update(s);
// System.out.println(update);
ArrayList<Stu> all = getAll();
System.out.println(all);
}
//新增数据
public static int inserts(Stu s) throws SQLException, ClassNotFoundException {
Connection getcon = DBLink.getcon();
String sql="insert into stu values(stu_sq.nextval,?,?,?)";
PreparedStatement ps = getcon.prepareStatement(sql);
ps.setString(1,s.getName());
ps.setString(2,s.getTel());
ps.setString(3,s.getAddr());
int i = ps.executeUpdate();
ps.close();
getcon.close();
return i;
}
//修改数据
public static int update(Stu s) throws SQLException, ClassNotFoundException {
Connection getcon = DBLink.getcon();
String sql="update stu set name=?,tel=?,addr=? where id=?";
PreparedStatement ps = getcon.prepareStatement(sql);
ps.setString(1,s.getName());
ps.setString(2,s.getTel());
ps.setString(3,s.getAddr());
ps.setInt(4,s.getId());
int i = ps.executeUpdate();
ps.close();
getcon.close();
return i;
}
//查询数据
public static ArrayList<Stu> getAll() throws SQLException, ClassNotFoundException {
Connection con=DBLink.getcon();
String sql="select *from stu";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
ArrayList<Stu> st=new ArrayList<>();
while (rs.next()){
Stu s=new Stu();
s.setId(Integer.parseInt(rs.getString("id")));
s.setName(rs.getString("name"));
s.setTel(rs.getString("tel"));
s.setAddr(rs.getString("addr"));
st.add(s);
}
return st;
}
}
通用方法的封装:
对于查找和增删改操作因为高度类似,我们可以进行简单的封装。
通用的连接数据库和关闭数据库代码的封装:
public class JDBCUtils {
static {
try {
Class.forName(PropUtils.get("jdbc.driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//连接数据库
public static Connection getConnection() {
try {
return DriverManager.getConnection(PropUtils.get("jdbc.url"), PropUtils.get("jdbc.username"), PropUtils.get("jbbc.password"));
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
//关闭数据库
public static void releaseResourse(ResultSet resultSet, Statement statement, Connection connection) {
try {
if (resultSet != null && !resultSet.isClosed()) {
resultSet.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if (statement != null && !statement.isClosed()) {
statement.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if (connection != null && !connection.isClosed()) {
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
增删改封装:
public class JDBCUtils {
static {
try {
Class.forName(PropUtils.get("jdbc.driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* @Description : 添加删除修改的通用方法
* @Param [sql, parama]
* @return int
*/
public static int saveOrUpdateOrDelete(String sql, Object... parama) {
Connection connection = getConnection();
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(sql);
for (int i = 0; i < parama.length; i++) {
ps.setObject(i + 1, parama[i]);
}
return ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
releaseResourse(null, ps, connection);
}
return 0;
}
/**
* @Description :查询的结果是单行单列时
* @Param [sql, param] 传一个sql,和对应的参数
* @return int
*/
public static int querySingle(String sql, Object... param) {
ResultSet rs = null;
PreparedStatement ps = null;
Connection con = null;
try {
con = getConnection();
ps = con.prepareStatement(sql);
for (int i = 0; i < param.length; i++) {
ps.setObject(i + 1, param[i]);
}
rs = ps.executeQuery();
if (rs.next()) {
return rs.getInt(1);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
releaseResourse(rs, ps, con);
}
return 0;
}
}
通用的查询方法:模拟配置文件的读取和查询操作
配置文件的格式如下:
<?xml version="1.0" encoding="utf-8" ?>
<jdbc>
<class name="org.example.pojo.student1" table="student1">
<id name="s_id" column="s_id" type="java.lang.Integer">
seq_student1
</id>
<property name="s_no" column="s_no" type="java.lang.String"></property>
<property name="s_name" column="s_name" type="java.lang.String"></property>
<property name="s_age" column="s_age" type="java.lang.Integer"></property>
<property name="s_sex" column="s_sex" type="java.lang.String"></property>
</class>
<class name="org.example.pojo.emp" table="emp">
<id name="empno" column="empno" type="java.lang.Integer">
seq_emp
</id>
<property name="ename" column="ename" type="java.lang.String"></property>
<property name="job" column="job" type="java.lang.String"></property>
<property name="mgr" column="mgr" type="java.lang.Integer"></property>
<property name="hiredate" column="hiredate" type="java.util.Date"></property>
<property name="sal" column="sal" type="java.lang.Double"></property>
<property name="comm" column="comm" type="java.lang.Double"></property>
<property name="deptno" column="deptno" type="java.lang.Integer"></property>
</class>
</jdbc>
取出各种属性值到map的方法:
用到了Dom4j这个依赖,这个依赖专门用来处理xml文件。
poi专门用来处理excel等文件格式
public class Dom4jUtils {
public static final Map<String, yyyzl> map = new HashMap<>();
private final static String path = "/jbdc.xml";
public static void readerSettings() {
SAXReader ss = new SAXReader();
try {
//获取根节点下的 /jbdc.xml
Document read = ss.read(Dom4jUtils.class.getResourceAsStream(path));
//获取根节点
Element rootElement = read.getRootElement();
//获取根节点下面的子节点 2个class
List<Element> elements = rootElement.elements();
for (Element e : elements) {
//将class中的name和table取出来
String name = e.attribute("name").getData().toString();
String table = e.attribute("table").getData().toString();
yyyzl y = new yyyzl();
y.setClassname(name);
y.setTablename(table);
//里面是class底下的一个个的标签,如id,property等
List<Element> elements1 = e.elements();
for (Element e1 : elements1) {
//取出他们中的name,column和type等标签内的元素
String pojoname = e1.attribute("name").getData().toString();
String columnname = e1.attribute("column").getData().toString();
String columntype = e1.attribute("type").getData().toString();
//如果是id的话,需要额外设置主键和序列
if (e1.getName().equals("id")) {
y.setPrimarykey(columnname);
y.setSequence(e1.getData().toString().trim());
}
yyyzlColumn column = new yyyzlColumn(pojoname, columnname, columntype);
y.getYzl().add(column);
}
map.put(name, y);
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
通用的查找方法:
public class yyyzlDao {
//读取到各类的属性值
static {
Dom4jUtils.readerSettings();
}
public Object getval(Serializable id, Class clasz) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
StringBuilder sql = new StringBuilder();
sql.append("select *from ");
String name = clasz.getName();
//通过name取到map数组中对应的属性值
yyyzl yzl = Dom4jUtils.map.get(name);
//取到表名
String tablename = yzl.getTablename();
sql.append(tablename + " where ");
//取到主键名
sql.append(yzl.getPrimarykey() + "=? ");
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = JDBCUtils.getConnection();
ps = con.prepareStatement(sql.toString());
ps.setObject(1, id);
rs = ps.executeQuery();
if (rs.next()) {
//反射传进来的类的Class
Object o = clasz.newInstance();
for (yyyzlColumn yzlcolumn : yzl.getYzl()) {
//取到列命
Object columnname = rs.getObject(yzlcolumn.getColumnname());
//取到pojo内的名,然后组合成类似setEname等格式的,方便反射,注意ename的e要大些
String methodname = "set" + StringUtils.upperCaseFirstWord(yzlcolumn.getPojoname());
//反射得到方法
Method method = clasz.getDeclaredMethod(methodname, Class.forName(yzlcolumn.getColumntype()));
if (method.getParameterTypes()[0] == java.lang.Integer.class) {
//根据类型判断,然后调用
method.invoke(o, Integer.parseInt(columnname.toString()));
}
if (method.getParameterTypes()[0] == java.lang.String.class) {
method.invoke(o, columnname == null ? null : columnname.toString());
}
if (method.getParameterTypes()[0] == java.lang.Double.class) {
method.invoke(o, Double.parseDouble(columnname == null ? "0" : columnname.toString()));
}
}
return o;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
// clasz.getMethod("")
return null;
}
}