`

jdbc笔记

    博客分类:
  • jdbc
阅读更多
连接数据的步骤
注册驱动
建立连接
创建执行sql的语句
执行语句
处理执行的结果
释放资源

1、加载驱动
2、写类
主要方法:
static void test() {
//注册驱动
//注册管理器,可以注册很多驱动。DriverManager里面有一个vector列表,会把所有的驱动都加入到该列表中
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver");按:分割开来
//Class.forName("com.mysql.jdbc.Driver");把类装载到jvm里面.从classpath里面去找,推荐使用这个方式
//关联到类的初始化过程
//当类被加载到虚拟机的时候,会调用静态代码块。在mysql的driver类中有一个静态代码块,是注册驱动的。

//建立连接
//连接的时候会使用url在vector中区匹配,如果有就建立连接。
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306:jdbc","root","");
//url格式:JDBC:子协议:子名称//主机名:端口/数据库

//创建执行sql的语句
Statement st = conn.createStatement();

//执行语句
ResultSet rs = st.executeQuery("select * from user");

//处理结果
User user = new User();
while(rs.next()) {
user.setName(rs.getString("name"));
user.setBirthday(rs.getDate("birthDay"));
user.setMoney(rs.getDouble("money"));
}
//释放资源
rs.close();
st.close();
conn.close();
//以上程序只是简单的连接,不严谨。需要改进。
}


//以模板方式获取连接
static void template() {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc","root","");
st = conn.createStatement();
rs = st.executeQuery("select * from user");
User user = new User();
while(rs.next()) {
user.setName(rs.getString("name"));
user.setBirthday(rs.getDate("birthday"));
user.setMoney(rs.getDouble("money"));
}
} catch (Exception) {
} finally {
try {
if(rs!=null) {
rs.close();
}
} finally {
try{
if(st!=null) {
st.close();
}
}finally{
if(conn!=null){
conn.close();
}
}
}
}

}
//工具类的使用,把class用final 修饰,不让继承,不让实例化,使用private实现构造函数。
public final class JdbcUiils{
private static String url = "";
private static String user = "";
private static String password = "";
private JdbcUtils(){}
static{
try{
Class.forName("com.mysql.jdbc.Driver");
}catch(ClassNotFoundException e){
throw new ExceptionInitializerError(e);
}
}
public static Connection getConnection()throws SQLException{
return DriverManager.getConnection(url,user,password);
}
public static void free(ResultSet rs,Statement st,Connection conn){
try{
if(rs!=null)
rs.close();
}catch(SQLException e1){
e1.printStackTrace();
} finally{
try{
if(st!=null)st.close();
}catch(SQLException e2){
e2.printStackTrace();
}finally{
conn.close();
}
}
}
}

//数据库的CRUD
static void read() {
}
static void create() {
String sql = "insert into user(name,birthday,money) values('name1','1987-01-01',400)";
String sql1 = "update user set money = money+2";
String sql2 = "delete from user where id>4";
st.executeUpdate(sql);//返回影响的行数,不管是增加,修改,删除。
}

//数据库注入问题;
select * from user where name = "or 1 or"
select * from user where name = '' or true or '';//什么条件都能满足.
//使用预编译语句PreareStatement,该接口继承Statement,不管增删改查都推荐使用preparestatement语句。
String sql = "select * from user where name=?";
PrepareStatement ps = conn.prepareStatement(sql);
ps.setString(1,name);
ps.executeQuery();
ResultSet rs = ps.executeQuery();

//数据类型与日期问题;
preparestatement和resultset有很多设置的数据类型;
sql.date从util.date继承过来的.
sql.date只有日期,没有时间。util.date有日期和时间。
String sql = "insert into user(name,birthday,money) values (?,?,?)";
ps = conn.preparestatement(sql);
ps.setString(1,name);
ps.setDate(2,new java.sql.Date(birthday.getTime()));
ps.setFloat(3,money);
ps.executeUpdate();
//读取时间
rs.getDate("列名");

//访问大段文本数据;
varchar最大255个字符。超过了就只能用clob类型、
在mysql中的clob类型叫做text.有些数据库就叫做clob类型。可以直接使用string来处理大文本字段。
写入大文本
File file = new File("src/cn/lulu/jdbc/JdbcUtils.java");
Reader reader = new BufferedReader(new FileReader(file));
ps.setCharacterStream(1,reader,(int)file.length());
读取大文本
Clob clob = rs.getClob(1);
Reader reader = clob.getCharacterStream();
File file = new File("JdbcUtils_bak.java");
//reader = rs.getCharacterStream(1);
Writer writer = new BufferedWriter(new FileWriter(file));
char[] buff = new char[1024];
for(int i=0;(i=reader.read(buff))>0;) {
writer.write(buff,0,i);
}
writer.close();
reader.close();


访问二进制的数据,比如图片或者压缩包,类型为Blob,使用InputStream,字节流
写入二进制
File file = new File("photo.jpg");
InputStream in = new BufferedInputStream(new FileInputStream(file));
ps.setBinaryStream(1,in,(int)file.length);
读取二进制
Blob blob = rs.getBlob(1);
InputStream in = blob.getBinaryStream();
//in = rs.getBinaryStream(1);
File file = new File("temp.jpg");
OutputStream out = BufferedOutputStream(new FileOutputStream(file));
byte[] buff = new byte[1024];
for(int i=0;(i=in.reader)>0;) {
out.write(buff,0,i);
}
out.close();
in.close();
//实际项目中如何应用jdbc,三层架构,jdbc在数据访问层
dao设计思想与骨架搭建。
定义dao接口
public interface UserDao{
public void addUser(User user);
public User getUser(int userId);
public User findUser(String name,String password);
public void update(User user);
public void delete(User user);
//结合service层的异常处理;
public void addUser(User user) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "insert into user(name,birthday,money) values(?,?,?)";
ps = conn.preparedStatement(sql);
ps.setString(1,user.getName());
ps.setDate(2,new java.sql.Date(user.getDate().getTime()));
ps.setFloat(3,user.getMoney());
ps.executeUpdate();
}catch(SQLException e){
e.printStackTrace();//异常处理不能隐藏掉。一般有catch模块就一定要处理,抛出或者返回。不然后面的代码还会接着执行。
throw new DaoException(e.getMessage(),e);
}finally{
JdbcUtils.free(rs,ps,conn);
}
}
}

//经典工厂模式,工厂一般都使用单例模式,然后要生产的东西定义为变量;
public class DaoFactory{
private static UserDao userDao = null;//一定要先定义工厂要生产的东西
private static DaoFactory instance = new DaoFactory();//因为是私有的构造函数,这个只能在类里面实例化。因为静态变量只是在内存中执行一次。
private DaoFactory(){
try{
Properties properties = new Properties();
//InputStream inStream = new FileInputStream(new File("src/temp.properties"));因为路径是写死的不方便,可以使用类加载器的方法加载文件,只要文件在classpath下,那么就会自己找到哪个文件所在位置。
InputStream inStream = DaoFactory.class.getClassLoader().getResourceAsStream("daoconfig.properties");
properties.load(inStream);
String userDaoClass = prop.getProperty("userDaoClass");
Class clazz = Class.forName(userDaoClass);
userDao = (UserDao)clazz.newInstance();//必须有一个缺省的构造方法;
} catch(Exception e) {
throw new ExceptionInInitializerError(e);
} finally {
inStream.close();
}
}
publ
ic static DaoFactory getInstance() {
return instance;
}
public UserDao getUserDao() {
return userDao;
}
}

//jdbc事务处理
原子性:组成事务处理的语句形成一个逻辑单元,不能只执行其中的一部分。
一致性:在事务处理执行前后,数据库是一致的。
隔离性:一个事务处理对另一个事务处理的影响。
持续性:事务处理的效果能够被永久保存下来。
connection.setAutoCommit(false);//打开事务
connection.commit();//提交事务;
connection.rollback();//回滚事务;
public void test() throws SQLException{
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false);
st = conn.createStatement();
String sql = "update user set money=money-10 where id=1";
st.executeUpdate(sql);
sql = "select money from user where id=2";
rs = st.executeQuery(sql);
float money = 0.0f;
if(money>300){
throw new RuntimeException("已经超过最大值");
sql = "update user set money = money+10 where id=2";
st.executeUpdate(sql);
conn.commit();
}
} catch (SqlException e) {
if(conn!=null) {
conn.rollback();
}
throw e;
} finally {
JdbcUtils.free(rs,st,conn);
}
}

//事务的保存点;
Savepoint sp = conn.setSavepoint();
conn.rollback(sp);
conn.commit();

//跨越多个数据源的事务,使用JTA容器实现事务。
分成两阶段提交
javax.transaction.UserTransaction tx = (UserTransaction)ctx.lookup("jndiName");
tx.begin();
tx.rollback();
tx.commit();//connection1和connection2可能来自不同的数据库;

//事务的隔离级别;
隔离级别多线程并发读取数据时的正确性
connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
脏读:一个事务读取了另一个未提交的并行事务写的数据。
不可重复读:一个事务重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务修改过。意思就是在同一个事务中读取的数据不一致。
幻读:一个事务读取的数量和另一个事务读取的数量不一致。就是一个事务中插入一条数据,但是该事务的操作是在另一个事务的周期内,导致另一个事务的数据不一致。
查看数据库默认的隔离级别:select @@tx_isolation;
设置数据库的格式级别:set transaction isolation level read_uncommitted;
打开事务:start transaction;

//jdbc调用存储过程,储存过程的难点不在于调用,而是在于如何写存储过程。
CallableStatement(从PreparedStatement扩展来的)
cs = connection.prepareCall("{call paname(?,?,?)}");
cs.registerOutParameter(index,Types.INTEGER);
cs.setXXX(i,XXX);
cs.executeUpdate();
int id = cs.getInt(index);
static void ps() throws SQLException {
Connection conn = null;
CallableStatement cs = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql ="{call addUser(?,?,?,?)}";
cs.conn.prepareCall(sql);
cs.registerOutParameter(4,Types.INTEGER);
cs.setString(1,"ps name");
cs.setDate(2,new java.sql.Date(System.currentTimeMillis()));
cs.setFloat(3,100f);
cs.executeUpdate();
int id = cs.getInt(4);
}catch(SQLException e) {
e.printStackTrace();
throw e;
}finally {
JdbcUtils.free(rs,cs,conn);
}
}
其他的几个API
PreparedStatement.getGeneratedKeys();
PreparedStatement ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
ps.executeUpdate();
ResultSet rs = st.getGeneratedKeys();
rs.getInt(1);

//批处理,可以大幅度提升大量增,删,改的速度。
PreparedStatement.addBatch();
PreparedStatement.executeBatch();
static void createBatch() throws SQLException{
Connecton conn = null;
PreparedStatement ps = null;
ResultSet rs = null
try {
conn = JdbcUtils.getConnecton();
String sql = "insert into user(name,birthday,money) values(?,?,?)";
ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
for(int i=0;i<1000;i++) {
ps.setString(1,"batch name"+i);
ps.setDate(2,new java.sql.Date(System.currenTimeMillis()));
ps.setFloat(3,100f+i);
ps.addBatch();
}
int[] is = ps.executeBatch();//执行的时候要用executeBatch();
} catch(SQLException e) {
throw e;;
} finally{
JdbcUtils.free(rs,ps,conn);
}
}



//可滚动的结果集,效率很低、
Statement st = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
ResultSet rs = st.executeQuery(sql);
rs.absolute(5);
rs.beforeFirst();
rs.afterLast();
rs.first();
rs.isFirst();
rs.last();
rs.isLast();
rs.moveToInsertRow();
//可更新的结果集
conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
rs.updateString("col name","new value");
rs.updateRow();


//DatabaseMetaData和ParameterMetaData
DatabaseMetaData meta = connection.getMetaData();
通过DatabaseMetaData可以获得数据库相关的信息,如:数据库版本,数据库名,数据库厂商信息,是否支持事务、是否支持某种事务隔离级别、是否支持滚动结果集等。
ParameterMetaData pmd = preparedStatement.getParameterMetaData();
通过ParameterMetaData可以获得参数的信息。
Connection conn = JdbcUtils.getConnection();
DatabaseMetaData meta = conn.getMetaData();
meta.getDatab号版本aseMajorVersion();//数据库主要
meta.getDatabaseProductName();//数据库名称,mysql
meta.supportsTransactions();//是否支持事务。非常多的数据库信息可以在里面找到。
//参数元数据
static void main() throws SQLException {
Object[] params = new Object[]{"lisi",100f};
read("select * from user where name=? and money >?",params);
}
static void read(String sql,Object[] params)throws SQLException{
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
ps = conn.preparedStatement(sql);
ParameterMetaDate meta = ps.getParameterMetaData();
int count = meta.getParameterCount();
for(int i=1;i<=count;i++) {
//meta.getparameterClassName(i);//java.lang.String
//meta.getParameterType(i);//12
//meta.getParameterTypeName(i);//varchar
ps.setObject(i,params[i-1]);//数组从0开始;
}
rs = ps.executeQuery();
while(rs.next()) {
rs.getString("name");
}
} fninally {
JdbcUtils.free(rs,ps,con);
}
}
分享到:
评论
1 楼 guanzhongdaoke54007 2011-11-26  

相关推荐

Global site tag (gtag.js) - Google Analytics