什么是jdbc
jdbc(Java DataBase Connectivity) java 数据库连接,用java来连接操作数据库;
客户端(java)------------》mysql服务端 TCP通信;
java 只提供一套连接的规范,即接口;具体实现由各个数据库厂商去完成
JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。
jdbc连接
- 导入jar包(实现类),
- 加载驱动类,反射拿到实现类:Class.Forname(“驱动类名”)
- DriverManger 拿到Connection
- Connection 拿到 Statement
- Statement 传输 sql 并返回结果集
- 处理结果
- 关闭资源
public void query() {
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
//加载驱动
Class.forName("com.jdbc.mysql.Driver");
//获取连接
String url = "jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf8&useSSL=false";
String username = "root";
String password = "root";
con = DriverManger.getConnection(url,username,password);
//拿到Statement
stmt = con.createStatement();
String sql = "select * from user";
rs = stmt.executeQuery(sql);
while(rs.next()) {
String username = rs.getString(1);
String password = rs.getString(2);
System.out.println(username + ", " + password);
}
} catch(Exception e) {
throw new RuntimeException(e);
} finally {
try {
if(rs != null) rs.close();
if(stmt != null) stmt.close();
if(con != null) con.close();
} catch(SQLException e) {}
}
}
jdbc 核心api
DriverManger (驱动管理器)
当数据库驱动被加载后(反射),就有驱动管理器来管理;
连接并返回获取到的连接
Connection 连接
连接获取 Statement
Statement
是用来向数据库发送SQL语句的,这样数据库就会执行发送过来的SQL语句
接受查询结果
- int executeUpdate (String sql) ,增,删,改操作,返回影响行数
- ResultSet executeQuery(String sql) 查询操作,返回结果集
- boolean execute(String sql) 给定指定的sql,可能返回多个结果,true ,有结果集,false ,没有结果集;
- 返回true,sql语句为查询语句,调用getResultSet()得到查询结果;
- 返回false,sql语句为非查询语句,调用getUpdateCount()得到受影响行数;
ResultSet 结果集
ResultSet 内部维护了一个行光标(类似于指针),默认指向第一行的前面;所以得next后才能拿到数据
- void beforeFirst():把光标放到第一行的前面,这也是光标默认的位置, 默认的结果集是无效的;
- void afterLast():把光标放到最后一行的后面, 默认的结果集是无效的;
- boolean first():把光标放到第一行的位置上,返回值表示调控光标是否成功, 默认的结果集是无效的;
- boolean last():把光标放到最后一行的位置上, 默认的结果集是无效的;
- boolean isBeforeFirst():当前光标位置是否在第一行前面;
- boolean isAfterLast():当前光标位置是否在最后一行的后面;
- boolean isFirst():当前光标位置是否在第一行上;
- boolean isLast():当前光标位置是否在最后一行上;
- boolean previous():把光标向上挪一行;默认的结果集是无效的
- boolean next():把光标向下挪一行;若下一行有数据,返回true;
- boolean relative(int row):相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行, 默认的结果集是无效的;
- boolean absolute(int row):绝对位移,把光标移动到指定的行上, 默认的结果集是无效的;
- int getRow():返回当前光标所有行。
- 获取结果集元数据!
- 得到元数据:rs.getMetaData(),返回值为ResultSetMetaData;
- 获取结果集列数:int getColumnCount()
- 获取指定列的列名:String getColumnName(int colIndex)
ResultSet提供了一系列的获取列数据的方法:
- String getString(int columnIndex):获取指定列的String类型数据;
- int getInt(int columnIndex):获取指定列的int类型数据;
- double getDouble(int columnIndex):获取指定列的double类型数据;
- boolean getBoolean(int columnIndex):获取指定列的boolean类型数据;
- Object getObject(int columnIndex):获取指定列的Object类型的数据。
- java.sql.Date getDate(int columnIndex): 获取指定列的java.sql.Date类型的数据
上面方法中,参数columnIndex表示列的索引**,列索引从1开始,而不是0**,这第一点与数组不同。如果你清楚当前列的数据类型,那么可以使用getInt()之类的方法来获取,如果你不清楚列的类型,那么你应该使用getObject()或者getString()方法来获取。
PreparedStatement的使用
PreparedStatement 是Statement的子接口
PreparedStatement 的好处:
- 防止sql攻击
- 提高代码的可读性
- 提高效率
使用:
- 使用Connection的prepareStatement(String sql):即创建它时就让它与一条SQL模板绑定;
- 调用PreparedStatement的setXXX()系列方法为问号设置值
- 调用executeUpdate()或executeQuery()方法,但要注意,调用没有参数的方法;
Class.forName("com.mysql.jdbc.Driver");
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/test_select? useUnicode=true&characterEncoding=utf8&useSSL=false","root","root");
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM emp WHERE deptno = ? ");
preparedStatement.setInt(1,deptno);
ResultSet resultSet = preparedStatement.executeQuery();
JDBC 工具类
public class JdbcUtils {
private static final String dbconfig = "dbconfig.properties";
private static Properties prop = new Properties();
static {
try {
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(dbconfig);
prop.load(in);
Class.forName(prop.getProperty("driverClassName"));
} catch(IOException e) {
throw new RuntimeException(e);
}
}
/**
*获取连接
*/
public static Connection getConnection() {
try {
return DriverManager.getConnection(prop.getProperty("url"),
prop.getProperty("username"), prop.getProperty("password"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 关闭方法
*/
public static void close(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet){
try {
if(connection!=null) connection.close();
if(preparedStatement!=null) preparedStatement.close();
if(resultSet!=null) resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* 增,删,改 方法
* @param sql
* @param pre
* @return
*/
public static int executeUpdate(String sql , Object...pre){
PreparedStatement preparedStatement = null;
try {
preparedStatement=getConnection().prepareStatement(sql);
if(pre!=null&&pre.length>0){
for (int i = 0; i < pre.length; i++) {
preparedStatement.setObject(i+1,pre[i]);
}
}
return preparedStatement.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return -1;
}
/**
* 查询方法
* @param sql
* @param clazz
* @param pre
* @param <T>
* @return
*/
public static List executeQyery(String sql,Class<?> clazz,Object...pre){
PreparedStatement preparedStatement = null;
try {
preparedStatement=getConnection().prepareStatement(sql);
if(pre!=null&&pre.length>0){
for (int i = 0; i < pre.length; i++) {
preparedStatement.setObject(i+1,pre[i]);
}
}
return parseResultSet(preparedStatement.executeQuery(),clazz);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
/**
* 解析结果集
* @param resultSet
* @param clazz
* @param <T>
* @return
*/
public static<T> List<T> parseResultSet(ResultSet resultSet,Class<?> clazz){
List<T> list = new ArrayList<>();
try {
T t = (T)clazz.newInstance();
Field[] declaredFields = clazz.getDeclaredFields();
int i = 0;
while(resultSet.next()){
while(i<declaredFields.length) {
declaredFields[i].setAccessible(true);
declaredFields[i].set(t, resultSet.getObject(declaredFields[i].getName()));
i++;
}
list.add(t);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return list;
}
}
properties 文件 :k-v键值对存储数据
Map的实现类: java.util.Properties类
void load(InputStream inStream)
方法,将输入流转换为Map的k,v键值对;
拿到输入流的方式一般是通过类加载器获取