JDBC (java database connection)
作用:是由sun公司提供的一套 jdbc api 可以使用纯java代码连接"任意"数据库
数据库连接操作
1.加载驱动 驱动:数据库厂商根据sun公司提供的接口 完成的对自己公司数据库连接的实现
Class.forName("oracle.jdbc.OracleDriver"); //加载驱动,注册Driver,利用反射原理
2.获取数据库连接(java.sql.Connection)
//getConnection( (协议:ip地址:端口号:数据库名字),用户名,密码 )
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "ami", "ami");
3.获取Statement对象,发送sql语句(java.sql.Statement)
Statement st = conn.createStatement(); //Statement 接口代表了一个数据库的状态
executeUpdate(String sql):int //返回值的作用,经常用来判断实际更新值是否与预期更新值相符
executeQuery(String sql):ResultSet
//当已知查询返回单条记录时使用if(rs.next())即可
while( rs.next() ){ // next()代表是否有一条数据 true代表有 进入while循环 false代表没有 不会进入while循环
int userid = rs.getInt("userid");
String uname = rs.getString("uname");
String pwd = rs.getString("upwd");
System.out.println( userid + " " + uname + " " + pwd );
}
4.关闭数据库连接(释放资源)
rs.close(); sta.close(); con.close();
依次依赖
按先ResultSet结果集,后Statement,最后Connection的顺序关闭资源,
因为Statement和 ResultSet 是需要连接时才可以使用的,
所以在使用结束之后有可能其它的 Statement 还需要连接,不能现关闭 Connection
PreparedStatement(Statement的子类)
使用Statement出现的问题:i.效率低 因为创建过多的字符串对象 ii.sql注入 //"aa"和123' or '1'='1
PreparedStatement ps = conn.prepareStatement(String sql); //预加载sql语句
占位符 ? //填充sql语句 //将SQL语句中取值发生变化的部分用占位符(?)代替
//给?赋值(也称参数绑定)
ps.setXXX(第几个占位符,值); //第几个占位符:“?”出现的次数
空值处理:如果要设置某个?取值为null,需要做如下操作:
ps.setObject(4, null); // 这种较好理解,建议使用
ps.setNull(4, java.sql.Types.DECIMAL);
// 第2参数为?对应列的数据类型,常量
模糊查询:
eg:String sql=" select * from emp where ename like ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,"%M%"); //强调:%的位置不是写在?附近,而是通过setString方法调用时传入
封装重复代码 DBUtils.java
工具类:XxxUtils.java //内部常写静态方法
java中的配置文件:xxx.properties
1)properties文件中格式采用key=value的形式
2)properties文件中的注释使用#开头
3)properties文件中不能出现中文(习惯上都是以ISO-8859-1编码)
//工具类,内部常写静态方法
public class DBUtils {
private static Properties pro = new Properties(); //获取Properties对象,需要设置static,类加载时分配空间 且 静态方法中只能调用静态属性
static{ //设置静态代码块,类加载时执行一次,只需要读取一次配置文件
InputStream is=null;
try {
is = new FileInputStream("src\\jdbc.properties"); //读取文件
pro.load(is); //加载输入流
} catch (Exception e) {e.printStackTrace();
}finally{
if(is!=null){ //关闭读写流
try{
is.close();
}catch(Exception e) {e.printStackTrace();}
}
}
}
// 声明一个静态的ThreadLocal变量,泛型表示它只能存取Connection类型的变量
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); //定义ThreadLocal对象
public static Connection getConnection(){ //静态方法,获取数据库连接
Connection conn = tl.get(); //先获取conn对象,如果是null,则继续执行,否则要直接返回
try {
if(conn==null){
Class.forName(pro.getProperty("Driver")); //加载驱动 //根据key值获取value值
conn = DriverManager.getConnection(pro.getProperty("url"),pro.getProperty("username"),pro.getProperty("userpassword")); //获取数据库连接
tl.set(conn); //保存conn对象到ThreadLocal中
}
} catch (Exception e) {e.printStackTrace();}
return conn;
}
public static void close(ResultSet rs,Statement st,Connection conn){ //静态方法,关闭资源
try {
if(rs!=null)rs.close();
if(st!=null)st.close();
if(conn!=null){
conn.close();
// 连接关闭后移除Thread中的conn对象
tl.remove(); //清除ThreadLocal对象,防止对下一个线程造成破坏
}
} catch (SQLException e) {e.printStackTrace();}
}
}
关闭资源:
由于Service(Biz) 和 Dao 公用了一个数据库连接,所以要在最后关闭数据库连接
如果中途关闭数据库连接,则会出现数据库连接已关闭这样的异常
在Biz中统一关闭数据库连接 DBUtils.close(null,null,conn);
在Dao中关闭ResultSet,Statement,但不关闭Connection DBUtils.close(rs,ps,null);
实体类 把数据库的数据存到的对象中
根据主键查询数据库后,会得到一组相关数据,这些数据共同描述了Java里关于一个对象的属性信息,
所以将这组数据提取封装成一个整体,方便数据在java程序之间的传递。
这个对象一般称为实体(entity,也称为JavaBean)。
Java实体类型与数据库对应关系:
Java实体类 ? 数据库表
实体类实例 ??? 表中一条记录
实体类OID ? 表主键
实体类普通属性 ? 表中列
标准实体Bean定义的语法要求:
属性全部私有
提供get/set方法
提供无参构造方法 //最好也提供有参构造方法
实现Serializable接口
对于可以为空的属性,定义时选择包装类型,以表示 null 值
Dao层(数据访问层) (database access object) 数据库访问模型
对一张表做增删改查等操作 --- 写到一个 类中
命名规范:BookDao.java
Biz层(业务逻辑层)(Service) (Business Object)
主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计
避免写重复的代码,因为有些功能需要同时增删除改查等操作,所以直接在业务层重复调用即可
命名规范:BookBiz.java | BookService.java
view层(视图层/显示层)
主要完成数据的录入和结果的展示
它面向的群体是真正的用户,主要负责接收用户的访问请求,收集完成请求所需数据
当处理结束后,向用户展示执行结果
事务
如果在一个事务中有多条sql语句, 我们希望某一条sql语句如果执行是失败了。
那么刚才执行成功的sql语句 能够(撤销执行)回滚
JDBC里默认的事务提交策略是执行成功一条记录就提交一次
conn.setAutoCommit(boolean a); //true自动提交,false手动提交
注意:此方法一经设置,永久生效。
经由这个conn执行的命令的结果都需要手动提交,不需要反复设置。
conn.commit();
conn.rollback(); //在Biz层回滚
conn.getAutoCommit(); //获取当前提交状态
ThreadLocal --为了保证Service(Biz) 中的 Connection 对象 和 Dao中的 Connection 对象是同一个
在当前自己的线程中保存一个对象到ThreadLocal中,
过一会,在当前线程中可以取出来刚才保存的对象
ThreadLocal<E> tl = new ThreadLocal<E>();
tl.set(value); //保存对象
tl.get(); //取出对象
tl.remove(); //清除ThreadLocal的对象
日期数据处理
如何得到一个java.util.Date对象
方法1:从字符串转换为日期
String dateStr = "1999-10-10";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
java.util.Date d = sdf.parse(dateStr);
方法2:从日历对象得到日期
Calendar c = Calendar.getInstance(); // 日历对象
c.set(1999,11,23);
java.util.Date d2 = c.getTime();
方法3:从一个毫秒值得到日期
java.util.Date d3 = new java.util.Date(System.currentTimeMillis()));
如何得到一个java.sql.Date对象 //获得java.sql.Time, java.sql.Timestamp与此类似
long time = new java.util.Date().getTime(); // 拿到毫秒时
// 通过毫秒值构造子类型对象
java.sql.Date sd = new java.sql.Date(time);
如何得到一个字符串时间值
java.util.Date date = new java.util.Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String time = sdf.format(date);