JDBC学习笔记
1.本质就是使用Java语言来操作数据库;由SUN提供接口规范,称为JDBC,数据库厂商提供的实现类,称为驱动。
2.连接数据库步骤:JDBC四大配置参数(驱动类名,url,用户名,密码);连接不同数据库就是配置参数不一样;
2.1:导jar包,即驱动;
2.2:加载驱动类:Class.forName("com.mysql.jdbc.Driver");必须是java.sql.Driver的实现类;加载驱动类(注册驱动);
2.2.1:所有java.sql.Driver的实现类,都提供了static块(在加载时执行),块内代码就是把自己注册到DriverManger中;
2.3:给出url,用户名,密码,使用DriverManeger得到connection对象:DriverManager.getConnection(url,name,pwd);
2.3.1:jdbc4.0后,每个驱动jar包下META-INF目录提供了一个java.sql.Driver文件,内容是接口的实现类名称,可不写2.2的语句;
2.4:异常:ClassNotFoundException,SQLException。
3.url协议格式:jdbc:厂商名称:子协议(厂商自定义);
3.1:mysql是jdbc:mysql://localhost:3306/dbname;
3.2:oracle的是jdbc:oracle:thin:@localhost:1521:mydb。
4.通过Connection对象创建Statement:con.createStatement(),向数据库发送语句,一般是DML语句;
4.1:增删改:Statement调用int executeUpdate(String sql),返回影响行数;
4.2:查询:Statement调用ResultSet executeQuery(String sql),返回ResultSet“表格”;
4.3:ResultSet:行光标,beforeFirst,AfterLast,判断行是否存在boolean next(),读取列的getXxx(列编号或列名);
4.4:关闭资源(倒关):ResultSet,Statement,Connection。
5.代码规范化:try外给出引用定义,try内为对象实例化,在finally进行关闭(里面还要套一层try进行非空判断才关闭,避免空指针异常)。
6.结果集特性:是否可滚动;是否敏感;是否可更新;在con.createStatement(int,int)得到Statement的时候,已经确定了;
6.1:最常用:不带参数,不滚动,不敏感,不可更新;
6.2:第一个参数:TYPE_FORWARD_ONLY(不滚动),TYPE_SCROLL_INSENSITIVE(滚动但不敏感),TYPE_SCROLL_SENTITIVE(滚动敏感,没实现);
6.3:第二个参数:CONCUR_READ_ONLY,CONCUR_UPDATABLE;
6.4:滚动结果集(可以任意滚动光标到首行、尾行、前移后移,返回当前行),默认的结果集不能滚动(只能next,但mysql默认可滚动);
6.5:获取结果集元数据:rs.getMetaData()返回ResultSetMetaData类型,可获得列数,列名等信息;改进:在循环取行的时候,可以先从元数据获得列数,再内循环取列,使用rs.getString(i)方法。
7.PrepareStatement:Statement子接口;优势:防SQL攻击;提高代码可读可维护性;提高效率;
7.1:获得PS:给出SQL模板,参数用?替代;调用con.prepareStatement(String sql);
7.2:使用PS调用setXxx(1,username)方法为?赋值;调用executeUpdate()或executeQuery()完成查询;
7.3:原理:服务器先校验语法,再编译,再执行(与函数类似);PS先把sql模板给数据库进行校验编译,然后执行时只传递参数;二次执行可直接执行;
7.4:默认mysql关闭预处理,需要在url给出useServerPrepStmts=true以及设置cachePrepStmts=true打开。
8.考虑封装获取连接代码到实用类中:
8.1:配置写到properties文件,然后使用classLoader.getResourceAsStream()读取,Properties对象的oad方法加载;
8.2:读取配置文件和加载驱动类费时,且多次连接只需要执行一次,所以把这两部分放到实用类的staic代码块,加载类时只执行一次。
9.DAO层的面向接口编程:即变动的东西放配置文件;OCP原则;
9.1:提供一个接口,一个实现类,一个工厂;service层使用工厂获得DAO实例;
9.2:工厂里使用配置文件读取得到实现类名称,然后反射(Class.forName().newInstance())得到实例;这样修改只需改配置文件,不改源代码;
9.3:案例:将以前底层使用xml存储的登录注册项目,增加一个DAO实现类改为JDBC连接数据库实现的,然后修改配置文件的实现类名称即可。
10.时间类型的转换:Date类在java中有两个,一个在util包下,一个在sql包下;
10.1:数据库的date,time,timestamp分别在java.sql下有对应的包;
10.2:领域对象中的所有属性不能出现java.sql下的所有东西;必须使用java.util.date;
10.3:PrepareStatement的set和ResultSet的get都是使用的java.sql.date;
10.4:sql到util:java.sql.date是java.util.date的子类型,直接赋值即可(其他两个也是);
10.5:util到sql:把util变成毫秒值,再创建sql的类型。
11.大数据:大的字节数据或字符数据;重点是硬盘文件到blob的转换,以及blob到硬盘文件的转换;
11.1:SQL标准提供小,一般,中等,大的blob和clob共8种类型;
11.2:mysql只提供了tinytext,text,mediumtext,longtext四种实现;
11.3:把mp3存数据库:pstmt.setBlob();重点在于从文件构造blob对象:commos-io包从文件构造byte数组;serialBlob构造方法构造blob对象;
11.4:注意在my.ini设置max_allowed_packet;
11.5:从数据库取mp3:rs.getBlob();把blob变成硬盘的文件:通过blob得到输入流;创建输出流。
12.批处理:批量增删改;PS内部有数组;
12.1:添加完一行参数后加上pstmt.addBatch();最后pstmt.executeBatch();
12.2:还需要打开mysql的批处理:url加上参数rewriteBatchedStatements=true。
13.所有事务的操作都是通过Connection对象完成;在try块里开启和提交事务,在catch块回滚事务;service层调用DAO的方法,还要传递同一个conn对象才能实现事务控制,但这样也违反了规则。
14.连接池:一个项目一个连接池即可;Java本身不提供连接池,但提供了规范:javax.sql.DataSource;连接池必须实现该接口;
14.1:参数:初始大小,最小空闲连接数,最大空闲连接数,增量,最大连接数,最大等待时间;
14.2:commons下的组件(Java第二api,这里不全):commons-dbcp,commons-pool,commons-dbutils;
14.3:DBCP连接池使用:a.创建连接池对象(new BasicDataSource());b.配置四大参数和连接池参数;c.获得连接对象;返回的conn对象是mysql驱动的conn对象的包装,对close()方法进行了增强(装饰),表示放连接回池中,而不是直接关闭。
15.装饰者模式:对象增强的手段:继承,装饰者模式,动态代理;
15.1:继承的缺点:增强的内容是死的,被增强的内容也是死的;类会增多;
15.2:装饰的增强内容是死的,但是被增强的内容可以任意修改(参数化);当不知道被增强对象的具体类型只知道其实现的接口或是某类的子类,可使用;
15.3:动态代理被增强对象可切换,增强内容也可切换;比如service和事务处理,增强后把事务开关放在配置文件里,即AOP;
15.4:在IO流里,主要的是字节流和字符流四大家族;FileInputStream是跟节点绑定在一起的,可传递File对象或String指定文件;
15.5:ByteArrayInputStream是节点流,跟内存中的byte []绑定在一起;
15.6:而BufferedInputStream则是装饰者,给一个InputStream就加缓冲区,不管被增强的内容是什么;ObjectInputStream、GZIPInputStream也是;
15.7:使用关键点:is a(实现同样的接口或继承同样父类),has a(被增强对象通过构造器传递进来),use a(其余方法使用底层对象完成),增强点。
16.C3P0连接池:开源免费,功能更强;使用了代理技术;配置可代码配置、默认配置、命名配置;
16.1:创建连接池:new ComboPooledDataSource();还要导jar包c3p0-pre,mchange-commons;
16.2:配置文件:规定的名字、位置;这样做之后可在代码里直接获得配置参数,就可省略配置代码;
16.3:配置文件除了默认配置还可有其他配置,在构造器里String指定不同配置名字即可。
17.JdbcUtils类:自己编写的与连接、事务有关的实用代码;
17.1:在DAO中处理事务简单,但DAO中不应该存在事务,只有数据库的基本访问;而service层不应该出现Connection,它只能在DAO出现;
17.2:思路:增加一个JdbcUtil,把获取连接(c3p0的方式),开启事务,提交回滚的代码放在这里,然后在service调用JdbcUtil和DAO代码完成业务;
17.3:难点:
17.3.1:DAO的SQL语句、JdbcUtil里提交、回滚使用的连接都必须是JdbcUtil开启事务获得的同一连接;
17.3.2:解决:JdbcUtil里储存一个事务专用连接对象,给提交回滚用,以及被DAO调用JdbcUtil函数获取;
17.3.3:JdbcUtil里的开启、提交、回滚前还得考虑健壮性的问题,避免空指针异常等。
18.JNDI:Java命名和目录接口;配置连接池到Tomcat,然后采用JNDI手段获取;
18.1:配置:Tomcat的conf的localhost下创建项目同名xml文件,<context>下配置资源名字,资源的BeanFactory和类型(固定的),以及资源相关参数;
18.2:获取:cxt=new InitialContext();ds=cxt.lookup("java:comp/env+资源名");
18.3:当然jar包不可缺;其实就是换了种方法配置连接池。
19.ThreadLocal:Thead类相当于人,Runnable类相当于任务;多线程并发的时候需要ThreadLocal对象;
19.1:内部就一个Map<Thread,T>容器,set/get/remove();以当前线程作键,只能存一个数据;
19.2:一般用在类的成员变量上,成员用ThreadLocal包装,这样多个线程访问都有自己的副本;
19.3:Spring把Connection放到了ThreadLocal中。
20.dbutils组件:commons-dbutils;可从问题解决出发一步步推导得到;解决增删改查调用重复代码问题;需要使用前面的JdbcUtils得到连接池;
20.1:问题1:实现增删改,需要DAO和实体类,每次操作变的只是sql语句和参数,重复代码多;
20.2:解决1:提取一个更新方法,将sql、参数参数化,然后正常从连接池获取连接,循环将sql赋参,然后执行更新;
20.3:问题2:查询比上面复杂点,需要加ORM代码;且发现实体类的set方法和rs的get方法,名字一致;
20.4:解决2:提取一个查询方法,将sql、参数和ORM映射代码(可定义一个接口让用户自己实现)参数化;
20.5:引出dbutils:new QueryRunner(连接池),然后按照上面qr.update(sql,params)和qr.query(sql,ResultSetHandler,params)即可;
20.6:ResultSetHandler接口可以自己实现T handle(ResultSet);也可以使用现成的实现类如new BeanHandler<Stu>(Stu.class)自动实现转换。

浙公网安备 33010602011771号