PreparedStatement

1.      PreparedStatement是Statement的子类,具有预编译的功能。可以将SQL语句变异之后在发送到数据库,具有余下优点

a) 由于编译之后才发送,解决了SQL注入问题,提高程序安全性

b)由于编译之后才发送,减轻了服务器压力,提高了程序性能

c) 由于可以设置占位符,是代码结构更清晰,提高代码可读性

 

2.      使用方式

Connection类中PreparedStatement prepareStatement(String sql)方法预编译SQL语句,获得一个PreparedStatement

SQL语句可以使用问号预设占位符

PreparedStatement类中多个setXxx()方法可以设置占位符的值,注意占位符从1开始

PreparedStatement类中int executeUpdate()可以预设SQL语句进行更新操作,返回影响行数,注意不要加参数

PreparedStatement类中ResultSet executeQuery()可以运行预设SQL语句进行查询操作,返回结果集

3.      查询代码显示

PreparedStatement st = conn.preparedStatement(“select id,name,password,email,birthday from user where name=?);

st.setString(1, name);

ResultSet rs = st.executeQuery();

4.更新代码示例

PreparedStatement st = conn.prepareStatement("insert into user(name,password,email,birthday) values(?,?,?,?)");

   st.setString(1, user.getName());

   st.setString(2, user.getPassword());

   st.setString(3, user.getEmail());

   st.setDate(4, new Date(user.getBirthday().getTime()));

st.executeUpdate();

大文本和二进制操作

1.1.1.      存储TEXT

PreparedStatement ps = conn.prepareStatement("insert into clob(file) values(?)");

File file = new File("src/cn/itcast/jdbc1/clob_blob/ClobDemo.java");

Reader reader = new FileReader(file);

ps.setCharacterStream(1, reader, (int) file.length());

ps.executeUpdate()

1.1.2.      读取TEXT

PreparedStatement ps = conn.prepareStatement("select file from clob");

ResultSet rs = ps.executeQuery();

if (rs.next()) {

      Reader reader = rs.getCharacterStream(int columnIndex);

      // 这个Reader就是从数据库中读取数据的流, 操作这个流来读取数据

}

 

1.2.      BLOB

BLOB用来存储大段的二进制数据, 例如图片, 音频, 视频. LONGBLOB最大4G

1.2.1.      存储BLOB

PreparedStatement ps = conn.prepareStatement("insert into big_binary(file) values(?)");

File file = new File("src/cn/itcast/jdbc1/clob_blob/IMG_0007.jpg");

InputStream in = new FileInputStream(file);

ps.setBinaryStream(1, in, (int) file.length());

ps.executeUpdate();

 

1.2.2.      读取BLOB

PreparedStatement ps = conn.prepareStatement("select file from big_binary");
ResultSet rs = ps.executeQuery();
if (rs.next()) {
   InputStream in = rs.getBinaryStream(1);
   // 这个InputStream就是从数据库中读取数据的流, 操作这个流来读取数据
}

 

2.        接口DAO

在实际应用中, 我们的JDBC代码通常都是在数据访问层, 也就是DAO层

 

为了解除Service层和DAO之间的耦合, 通常会定义一个DAO接口, 其中包含各种对实体的操作

 

由于实际操作数据库可能使用各种不同技术, 但只要都实现之前定义好的接口, Service层通过接口就可以调用DAO层的代码了

 

在更换底层DAO的时候, Service层的代码由于都是针对接口调用而不需要改变.

 

 

3.        工厂模式

场景和问题:java程序开发讲究面向借口,隐藏具体的实现类。

解决方案:可以使用工厂方法,又成为简单工厂的设计模式。

工厂模式中主要用createXXX()或getFactory()方法来返回接口,并且在该方法内部创建实现类。

工厂模式中主要涉及:接口,实现类,工厂类(返回接口并且创建实现类)和调用类。

工厂模式的本质:重在选择,在工厂模式中起重要作用的是各种类,工厂只提供功能接口;选择功能的实现:外部传入参数或者从配置文件中获取。

工厂模式使用的步骤:首先创建一个接口,然后创建若干个实现接口的类,第三创建工厂类并且提供返回接口的方法createXXX();最后在其他的类中调用工厂中的接口。

 

工厂模式是指在Service层中不直接创建DAO层对象, 而是通过一个工厂类来读取配置文件创建.

 

在更换DAO层的实现时只要修改配置文件就可以, 不需对所有Service中的代码更改, 提高代码的维护性.

 

写一个单例工厂, 工厂中根据配置文件生成DAO, 提供方法获取DAO.

4.        分页

通过ResultSet的滚动可以设置获取记录的位置, 但这样是从数据库中查询出所有数据, 然后再从结果中筛选结果, 性能非常低.

 

MySQL提供了分页语法. 在查询语句后可使用LIMIT关键字完成分页功能, 例如:

 

select * from user limit 40,20

 

查询从user表中取出从第41条开始的20条记录. 第一个参数表示忽略前面多少个, 第二个参数代表取多少个.

5.        可更新结果集、敏感结果集

conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

 

ResultSet.TYPE_SCROLL_SENSITIVE

表示获得ResultSet之后是敏感的, 随数据库更新的. 但MySQL没有支持这项功能

 

ResultSet.CONCUR_UPDATABLE

表示获得ResultSet之后是可更新的, 例如:

rs.next();

rs.updateString("name", "updateName");

rs.updateRow();

可以将当前行的name属性改为updateName.