类似于javase的反射
0 元数据概念:
a) 数据的定义数据
b) 数据库,表,列等信息也是一种对象,他们也是由最基础的数据组建而成,基础组件就叫做元数据。
1 数据库元数据: DataBaseMetaData
a) 获取方式: connection.getMetaData();
b) 常用方法说明:
getURL() | 返回一个String类对象,代表数据库的URL。 |
getUserName() | 返回连接当前数据库管理系统的用户名。 |
getDatabaseProductName() | 返回数据库的产品名称。 |
getDatabaseProductVersion() | 返回数据库的版本号 |
getDriverName() | 返回驱动驱动程序的名称 |
getDriverVersion() | 返回驱动程序的版本号 |
isReadOnly() | 返回一个boolean值,指示数据库是否只允许读操作 |
代码如下:
public static void main(String[] args) {
try {
Connection conn = JdbcUtils.getConnection();
DatabaseMetaData dbmetadata = conn.getMetaData();
String url = dbmetadata.getURL();
String username = dbmetadata.getUserName();
String dbProName = dbmetadata.getDatabaseProductName();
String dbProVersion = dbmetadata.getDatabaseProductVersion();
String driverName = dbmetadata.getDriverName();
String diriverVersion = dbmetadata.getDriverVersion();
boolean readonly = dbmetadata.isReadOnly();
System.out.println("url: " + url);
System.out.println("username: " + username);
System.out.println("dbProName: " + dbProName);
System.out.println("dbProVersion: " + dbProVersion);
System.out.println("driverName: " + driverName);
System.out.println("diriverVersion: " + diriverVersion);
System.out.println("readonly: " + readonly);
} catch (SQLException e) {
e.printStackTrace();
}
}
结果:
url: jdbc:mysql://localhost:3306/jdbc
username: root@localhost
dbProName: MySQL
dbProVersion: 5.0.96-community-nt
driverName: MySQL-AB JDBC Driver
diriverVersion: mysql-connector-java-5.0.8 ( Revision: ${svn.Revision} )
readonly: false
2 参数元数据:
a) 获取方式: preparedStatement.getParameterMetaData();
b) 常用方法说明:
getParameterCount() | 获得指定参数的个数 |
getParameterType(int param) | 获得指定参数的sql类型 |
代码如下:
// 参数元数据
public static void test1(){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from account where id=? and name=?";
st = conn.prepareStatement(sql);
ParameterMetaData meta = st.getParameterMetaData();
System.out.println(meta.getParameterCount());
//int i = meta.getParameterType(1); // 1 数据类型都放在 Types, in java.sql.Types中,用整数表示 2 mysql驱动对此方法支持不利 方法执行不了
System.out.println(i);
}catch(Exception e){
e.printStackTrace();
}
finally {
JdbcUtils.release(rs, st, conn);
}
}
结果:
2
3 结果集元数据:
a) 获取方式:resultSet.getMetaData();
b) 常用方法说明:
getColumnCount() | 返回resultset对象的列数 |
getColumnName(int column) | 获得指定列的名称 |
getColumnTypeName(int column) | 获得指定列的类型 |
代码如下:
// 结果集元数据
public static void test2(){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from user";
st = conn.prepareStatement(sql);
rs = st.executeQuery();
ResultSetMetaData meta = rs.getMetaData();
System.out.println(meta.getColumnCount());
System.out.println(meta.getColumnName(2)); // 参数角标从1开始
}catch(Exception e){
e.printStackTrace();
}
finally {
JdbcUtils.release(rs, st, conn);
}
}
结果为:
5
name
4 自定义o-r mapping映射框架实现dml:
a) 所有实体的CUD操作代码基本相同,仅仅发送给数据库的SQL语句不同而已,因此可以把CUD操作的所有相同代码抽取到工具类的一个update方法中,并定义参数接收变化的SQL语句。
b) 实体的R操作,除SQL语句不同之外,根据操作的实体不同,对ResultSet的映射也各不相同,因此可义一个query方法,除以参数形式接收变化的SQL语句外,可以使用策略模式由qurey方法的调用者决定如何把ResultSet中的数据映射到实体对象中。
c) 在查询中,因为使用到反射,因此表中属性要和javabean属性保持一致(大小写),否则映射不过去报java.lang.NoSuchFieldException
代码如下:
自定义o-r mappping dml写法:
interface ResultSetHandler{
public Object handler(ResultSet rs);
}
/**
* 把查询结果封装到bean中
* public Customer find(int id) throws SQLException {
String sql = "select id,name,sex,birthday,cellphone,email,preference,type,description from customer where id=?";
Object params[] = {id};
return (Customer) JdbcUtils.query(sql, params, new BeanHandler(Customer.class));
}
*
*/
class BeanHandler implements ResultSetHandler{
// 封装到实际对象的类型
private Class clazz;
public BeanHandler(Class clazz){
this.clazz = clazz;
}
// javabean数据封装
public Object handler(ResultSet rs) {
try{
Object obj = clazz.newInstance();
if(!rs.next()){
return null;
}
ResultSetMetaData meta = rs.getMetaData();
int count = meta.getColumnCount();
for(int i=0;i<count;i++){
// 得到每一列 的名称和值
String columnName = meta.getColumnName(i+1);
Object value = rs.getObject(i+1);
// 通过反射得到 每一列列名 区域,然后在把值给设置进来
Field f = clazz.getDeclaredField(columnName);
f.setAccessible(true);
f.set(obj, value);
}
return obj;
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
/**
* 把查询结果封装到集合中
* public List getAll() throws SQLException{
String sql = "select * from customer";
Object params[] = {};
return (List) JdbcUtils.query(sql, params, new ListBeanHandler(Customer.class));
}
*/
class ListBeanHandler implements ResultSetHandler{
private Class clazz;
public ListBeanHandler(Class clazz){
this.clazz = clazz;
}
public Object handler(ResultSet rs) {
try{
if(rs==null){
return null;
}
ResultSetMetaData meta = rs.getMetaData();
int count = meta.getColumnCount();
List list = new ArrayList();
while(rs.next()){
Object obj = clazz.newInstance();
for(int i=0;i<count;i++){
String columnName = meta.getColumnName(i+1);
Object value = rs.getObject(i+1);
Field f = clazz.getDeclaredField(columnName);
f.setAccessible(true);
f.set(obj, value);
}
list.add(obj);
}
return list;
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
public class JdbcUtils {
/*private static String driver = "com.mysql.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/jdbc2";
private static String username = "root";
private static String password = "root";*/
/*
private static String driver = "oracle.jdbc.driver.OracleDriver";
private static String url = "jdbc:oracle:thin:@localhost:1521:orcl";
private static String username = "scott";
private static String password = "tiger";*/
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static{
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("bj/util/db.properties");
Properties prop = new Properties();
prop.load(in);
driver = prop.getProperty("driver");
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
Class.forName(driver);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url,username,password);
}
public static void release(ResultSet rs,Statement st,Connection conn){
if(rs!=null)
{
try{
rs.close();
}catch(Exception e){
e.printStackTrace();
}
rs = null;
}
if(st!=null)
{
try{
st.close();
}catch(Exception e){
e.printStackTrace();
}
st = null;
}
if(conn!=null){
try{
conn.close();
}catch(Exception e){
e.printStackTrace();
}
conn = null;
}
}
/*
* DBUtils工具类的 增删改 原理代码
* 用Object数组接受传递参数的个数和类型
*/
public static void update(String sql,Object params[]) throws SQLException{
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
st = conn.prepareStatement(sql);
for(int i=0;i<params.length;i++){
st.setObject(i+1, params[i]);// 给参数赋值时,PreparedStatement角标从1开始,因此第一个参数为i+1
}
st.executeUpdate();
}finally{
JdbcUtils.release(rs, st, conn);
}
}
/*
* 策略模式:1 在查询到数据后,让方法的调用者来处理 获取db数据和映射实体之间转换工作, 2 定义公共接口约定调用者实现细则时要遵守的细则
* DBUtils工具类的 查询 原理代码
*/
public static Object query(String sql,Object params[],ResultSetHandler rh) throws SQLException{
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
st = conn.prepareStatement(sql);
for(int i=0;i<params.length;i++){
st.setObject(i+1,params[i]);
}
rs = st.executeQuery();
// 交给调用者传递的处理类将db返回结果和业务实体bean封装
return rh.handler(rs);
}finally{
JdbcUtils.release(rs, st, conn);
}
}
}
5 常用O-R Mapping映射工具
a) Hibernate:现在用的少了
b) Ibatis: 现在一般用的是 mybatis
c) Commons DbUtils(只是对JDBC简单封装)