三.Dao模式
这个是非常重要的模式。主要是运用分层,分为实体层,Dao层,Util层,DaoIml层和测试层。
实体层:主要封装了数据库一些字段。
Dao层主要是接口,定义各种方法,做什么。
DaoIml层主要是实现接口层的各种方法
Util层主要写了一些通用方法和数据库的开启和关闭
测试层顾名思义就是测试
下面我们通过对数据库的操作来对Dao模式进行一个了解。首先,敲代码之前要考虑吧代码的复用性
一 一个增加的方法
1,连接数据库的两种方法在上面已经提到过,放到Util包下即可,这里不在说明。
2,在实体类封装数据库字段,首先,你要保证你有这张即将操作的表,其次,字段名和你封装的名一致。
3,在接口中定义插入方法,即Dao层下
这个方法有一个整形返回值,主要是利用返回值来判断是否插入成功,并且该方法一个类对象参数,主要是把要插入的字段存入这个类对象中,这个类对象中的属性正好又和数据库的字段对应,这就是我们在实体类封装的时候做的。
4 创建实现接口类,并且实现插入方法
这里插入的值便从类对象里面获取,操作和正常插入操作没有什么不同
5在测试类中添加数据
红线是接口引用具体子类,调用子类的具体方法
这样便以Dao模式的方式实现了数据的插入,查询,删除,修改和此类似。
写到这里,我们可以思考一下,每次修改,插入,删除的过程都差不多,只是SQL语句和参数的不同,我们可不可以定义一个方法来增强代码的复用性呢?通过一个方法,其他类来调用或重写?当然可以,SQ语句和参数不同,我们可以把这两个作为参数来传递,谁调用,谁来传参数来决定是增加或者删除,SQL语句的参数决定了是什么类型,即删除还是增加,另一个参数束腰是SQL语句里面的条件什么的。这里你肯定该想为什么是增删改,而没有查询呢,因为查询会返回一个结果集对象,还需要进行遍历,与增删改不同,不过我们在后面也可以定义一个查询的通用方法。
一,增删改通用方法
1考虑到代码的复用性,我们把这个方法写在Util包中开启和关闭数据库连接的类中,其他需要这个方法的继承这个类就好。
2主要是参数那里,在上面,相信我已经说的很详细了,然后我们在接口中定义一个查询方法吧。
这个方法名和前面那个Util类方法并没有多大的关系,那个方法只需要在最后调用,注意体会方法的参数和返回值
3然后再实现类中实现这个方法
只需要在实现类的实现方法中定义SQKL语句和需要传的SQL参数就可,如果SQL参数为空,可以传一个NULL过去,这样就实现了增删改的通用。
4最后在测试类通过set方法添加上数据即可,和上面一样
JDBC总结
一:主要是JDBC链接
格式主要为:加载驱动:Class.forName(oracle:jdbc:OracleDrivaer);
创建链接Connection con = DriverManager(jdbc:orcale:thin:@localhost:1521:orcl2);
然后通过PreparedStatement pstmt = con.prepareStatement(sql),创建执行SQL语句,最后执行
pstmt.executeUpdate()或者pstmt.executeQuery();
使用PreparedStatement比Statement的好处主要是能够防止SQLde注入,在安全性要好的多,建议使用前者。
JDBC的链接可以考虑一下代码的复用性:1创建一个类,把链接的代码封装成一个方法,需要用的时候在调用,但这种方法每次调用都需要加载驱动,关闭后还得重新开启链接
2创建Properties文件(在项目根目录下创建),把需要用的属性加载进去,通过第三方软件进行读取,获得链接,好处是 每次申请不需要再进行加载驱动,关闭链接后会被回收,下面介绍如何使用这种方法。
1, 填写配置文件:
2, 导入第三方包
利用链接池来进行JDBC的链接主要需要导入三个包,加上JDBC本身的链接还需要导入一个包,一共需要导入4个包。
3, 编写代码
Properties po = new Propertier();
po.load(new FileInputStream(“Properties文件名”));
DataSource da = BasicDataFactory.createDataSource(po);
//这里主要是运用工厂模式来创建对象,不需要通过New,回去可以复习一下工厂模式。
con = da.getConnection();
好了,这样一个通过连接池链接数据库的工作就完成了。
二:JDBC大数据操作
大数据操作这里,主要是分为cblob和blob两种类型数据的文件,前者主要存储一下长的字符串,后者主要通过二进制来存储一些图片、音频之类的,不过,在数据库中通常存的是图片或者视频的路径,很少存源文件。
1 clob介绍
链接数据库的操作上面已经介绍过,下面不在重复
PreperdStatement pstmt = con.preparestatement(insert into table values(?,?));
String str=”要存入长字符串”;
StringReader reader = new StringReader(str);
//StringReader这里运用这个方法主要是为了下面setCharacterStream方法服务,它的参数要求需要用到reader对象,StringReader方法主要是通过字符流的方式读取字符串
pstmt.setCharacterStream(index,reader,length),//第1个参数主要是对应sql语句中的第几个问号,第二个参数就是前面创建的
、StringReader对象,第三个参数是reader的长度。
2 blob介绍
主要存储一些图片之类的文件,前提别忘了在数据库创建该类型的字段。
思想主要是:先创建一个字段用来存入图片,先把这个字段存入一个空数据(empty_blob()),然后更新它,更新为图片或者音频。
1, String sql = (“insert into table values(empty_blob())”);
2, pstmt =con.preparedstatement(sql);
3, pstmt.executeUpdate();
这就成功的向里面插入了一个空值。然后查询这个空值并且更新它
1 sql=(”select * (blob字段名) from table where id=(对应的ID值)for update(尤其重要)”)
2 pstmt = con.preparedstatement(sql);
3 ResultSet rs = pstmt.executeQuery();
4 if(rs.next()){
5 Bolob b = (Bolob)rs.getBlob(“大数据字段名”);
6 OutPutStream os = b.setBinaryStream(1L);
7 (当前类名).class.getResourceAsStream(“图片路径或者音频路径”);
8 Int len =0;
9 Byte [] temp = new Byte[1024];
10 while((len = is.read(temp))!=-1){
os.write(temp,0,len);
os.flush();
11 }
12 con.commit();
13
14 }
查询通用方法:
先说一下思路,增删改查方法,方法参数通常由一个SQL语句和SQL语句里面的参数组成,由于SQL语句参数的数量是不定的,我们首先要对这个SQL语句参数数量进行判断,其次,得到的结果集列的数量也是不定的,我们需要动态的获取SQL查询的列。
这里需要用到getMetaData()和getColumnCount()这两个方法。解决了这两个问题,便可以开始写查询通用方法了。
1:声明一个public List executeQuery(String sql,Object[]params)方法
2:con = getConnect() //把链接数据库的方法封装到父类的getConunt()中,这里直接调用就好了
3:Lsit table = new ArrayList();//用来装载查询出来的每一行数据
3: PreparedStatement ps = con.preparedStatement(sql)//这里的SQL不需要再定义,而是通过调用的时候传参数过来,这样来实现SQL的通用,SQL语句的定制化解决,下面便开始来考虑SQL语句中参数,当然,是如果有的话
4: for(inti=0;i<params.length;i++){
pstmt.setObject(i+1,paramsp[i]);//这里可能会抛出异常,为什么要用setObject呢,因为考虑到兼容性的问题,使用Object可以涵盖大部分数据类型,包装数据类型的插入成功。
}
5:ResultSet rs = ps.executeQuery();
ResultSetMetaData meta = rs.getMetaData();
Int num = meta.getColumnCount //这几行代码是执行查询语句,和获得每一行对应的有几列,拿到这个数据之后,我们可以遍历出这个查询语句中有几个字段。
6:while(rs.next()){
遍历出每一行数据,每一行对应一个rowList;
for(int i=0;i<num;i++){
row.add(I,res.getObject(i+1));//把每一行的数据存入row里面
}
table.add(row);//内层循环结束一次,代表一行的数据已经存储完毕,然后把这一行的数据装入table里面
}
return table;
}
使用连接池链接数据库不需要关闭connection流
最后还有两步,在接口中定义一个查询方法,返回一个List实现类中重写,定义完SQL语句和数组参数之后返回调用一下我们刚刚写过的方法就好,值得注意的是,在最后遍历数据的时候,也是需要两次循环的,外层循环遍历出的每一行的数据,内层循环遍历出的是每一个字段的值。
测试方法遍历出数据到控制台