简介:
- JDBC(Java DataBase Connectivity)就是Java数据库连接,实际上就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。
- JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。
- JDBC中的核心类有:DriverManager、Connection、Statement,和ResultSet!
//加载驱动
Class.forName("com.mysql.jdbc.Driver")
//获取连接
Connection con = DriverManager.getConnection(“jdbc:mysql://localhost:3306/mydb1”,”root”,”123”);
//得到声明
Statement stmt = con.createStatement();
//sql语句
String sql = “insert into user value(’zhangSan’, ’123’)”;
//执行更新sql
int m = stmt.executeUpdate(sql);(这里的m指的是影响的行数)
//执行查询sql
ResulSet rs=stmt.executeQuery(sql);
rs.next();
rs.getString(下标);(下标是从1开始,而不是从零)
- 关闭流(倒关)
rs.close();
stmt.close();
con.close(); - void beforeFirst():把光标放到第一行的前面,这也是光标默认的位置;
void afterLast():把光标放到最后一行的后面;
boolean first():把光标放到第一行的位置上,返回值表示调控光标是否成功;
boolean last():把光标放到最后一行的位置上;
boolean isBeforeFirst():当前光标位置是否在第一行前面;
boolean isAfterLast():当前光标位置是否在最后一行的后面;
boolean isFirst():当前光标位置是否在第一行上;
boolean isLast():当前光标位置是否在最后一行上;
boolean previous():把光标向上挪一行;
boolean next():把光标向下挪一行;
boolean relative(int row):相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行;
boolean absolute(int row):绝对位移,把光标移动到指定的行上;
int getRow():返回当前光标所有行。 - con.createStatement():生成的结果集:不滚动、不敏感、不可更新!
con.createStatement(int,int):
第一个参数:
ResultSet.TYPE_FORWARD_ONLY:不滚动结果集;
ResultSet.TYPE_SCROLL_INSENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化;
ResultSet.TYPE_SCROLL_SENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化;
第二个参数:
CONCUR_READ_ONLY:结果集是只读的,不能通过修改结果集而反向影响数据库;
CONCUR_UPDATABLE:结果集是可更新的,对结果集的更新可以反向影响数据库。
- Statement createStatement(int resultSetType, int resultSetConcurrency)
- PreparedStatement(它是Statement接口的子接口)
作用:防SQL攻击;提高代码的可读性、可维护性、提高效率
String sql = “select * from tab_student where s_number=?”;
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, “S_1001”);
ResultSet rs = pstmt.executeQuery();
rs.close();
pstmt.clearParameters();//每次执行需要清空的
pstmt.setString(1, “S_1002”);
rs = pstmt.executeQuery();
- JdbcUtils工具类
public class JdbcUtils {
private static final String dbconfig = "dbconfig.properties";
static {
try {
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(dbconfig);
private static Properties prop = new Properties();
prop.load(in);
Class.forName(prop.getProperty("driverClassName"));
} catch(IOException e) {
throw new RuntimeException(e);
}
}
public static Connection getConnection() {
try {
return DriverManager.getConnection(prop.getProperty("url"),
prop.getProperty("username"), prop.getProperty("password"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
- 经过class.forName()得到Class之后,调用newInstance()的到对象
时间类型
- java.sql包下给出三个与数据库相关的日期时间类型,分别是:
Date:表示日期,只有年月日,没有时分秒。会丢失时间;
Time:表示时间,只有时分秒,没有年月日。会丢失日期;
Timestamp:表示时间戳,有年月日时分秒,以及毫秒。 - 数据库类型与java中类型的对应关系:
DATE -> java.sql.Date
TIME -> java.sql.Time
TIMESTAMP -> java.sql.Timestamp - 时间类型的转换:
java.util.Date 转换为 java.sql.Date、Time、Timestamp
把util的Date转换成毫秒值
使用毫秒值创建sql的Date、Time、Timestamp
java.util.Date date = new java.util.Date();
long l = date.getTime();
java.sql.Date sqlDate = new java.sql.Date(l);
海量数据
- 标准SQL中提供了如下类型来保存大数据类型:
类型 长度
tinyblob (256B)
blob (64K)
mediumblob(16M)
longblob (4G)
tinyclob (256B)
clob (64K)
mediumclob (16M)
longclob(4G) - mysql中使用如下四种类型来处理文本大数据:
类型 长度
tinytext (256B)
text (64K)
mediumtext (16M)
longtext (4G)
装入
con = JdbcUtils.getConnection();
String sql = "insert into tab_bin(filename,data) values(?, ?)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, "a.jpg");
InputStream in = new FileInputStream("f:\\a.jpg");[得到一个输入流对象]
pstmt.setBinaryStream(2, in);[为第二个参数赋值为流对象]
pstmt.executeUpdate();
取出:
con = JdbcUtils.getConnection();
String sql = "select filename,data from tab_bin where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, 1);
rs = pstmt.executeQuery();
rs.next();
String filename = rs.getString("filename");
OutputStream out = new FileOutputStream("F:\\" + filename)[使用文件名来创建输出流对象。];
InputStream in = rs.getBinaryStream("data")[读取输入流对象];
IOUtils.copy(in, out)[把in中的数据写入到out中。];
out.close();
批处理
- 批处理只针对更新(增、删、改)语句
- 可以多次调用Statement类的addBatch(String sql)方法,把需要执行的所有SQL语句添加到一个“批”中,然后调用Statement类的executeBatch()方法来执行当前“批”中的语句。
- void addBatch(String sql):添加
- int[] executeBatch():执行所有
- void clearBatch():清除
- 当执行了“批”之后,“批”中的SQL语句就会被清空!
PreparedStatement批处理
PreparedStatement的批处理有所不同,因为每个PreparedStatement对象都绑定一条SQL模板。所以向PreparedStatement中添加的不是SQL语句,而是给“?”赋值。
con = JdbcUtils.getConnection();
String sql = "insert into stu values(?,?,?,?)";
pstmt = con.prepareStatement(sql);
for(int i = 0; i < 10; i++) {
pstmt.setString(1, "S_10" + i);
pstmt.setString(2, "stu" + i);
pstmt.setInt(3, 20 + i);
pstmt.setString(4, i % 2 == 0 ? "male" : "female");
pstmt.addBatch()[PreparedStatement的addBatch()方法没有参数!];
}
pstmt.executeBatch[执行批]();
数据库连接池
- 实现:必须实现 javax.sql.DataSource接口
- 概念:
用池来管理Connection,这可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。
DBCP
- DBCP是Apache提供的一款开源免费的数据库连接池
public void fun1() throws SQLException {
BasicDataSource ds = new BasicDataSource();
ds.setUsername("root");
ds.setPassword("123");
ds.setUrl("jdbc:mysql://localhost:3306/mydb1");
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setMaxActive(20);
ds.setMaxIdle(10);
ds.setInitialSize(10);
ds.setMinIdle(2);
ds.setMaxWait(1000);
Connection con = ds.getConnection();
System.out.println(con.getClass().getName());
con.close();
}
C3P0(性能优于DBCP)
- C3P0也是开源免费的连接池!
- C3P0中池类是:ComboPooledDataSource。
public void fun1() throws PropertyVetoException, SQLException {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb1");
ds.setUser("root");
ds.setPassword("123");
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setAcquireIncrement(5);
ds.setInitialPoolSize(20);
ds.setMinPoolSize(2);
ds.setMaxPoolSize(50);
Connection con = ds.getConnection();
System.out.println(con);
con.close();
}
- 配置文件要求:
文件名称:必须叫c3p0-config.xml
文件位置:必须在src下
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<-- 默认配置 -->
<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123</property>
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</default-config>
<-- 指定数据库(oracle)配置 -->
<named-config name="oracle-config">
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123</property>
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</named-config>
</c3p0-config>
- c3p0的配置文件中可以配置多个连接信息,可以给每个配置起个名字,这样可以方便的通过配置名称来切换配置信息。
ThreadLocal
- ThreadLocal类只有三个方法:
void set(T value):保存值;
T get():获取值;
void remove():移除值。 - ThreadLocal的内部是Map
ThreadLocal内部其实是个Map来保存数据。它使用了当前线程做为键。
class MyThreadLocal<T> {
private Map<Thread,T> map = new HashMap<Thread,T>();
public void set(T value) {
map.put(Thread.currentThread(), value);
}
public void remove() {
map.remove(Thread.currentThread());
}
public T get() {
return map.get(Thread.currentThread());
}
}
DBUtils
- DBUtils简介
DBUtils是Apache Commons组件中的一员,开源免费!
DBUtils是对JDBC的简单封装!
DBUtils的Jar包:dbutils.jar- DBUtils主要类
update():执行insert、update、delete!
query():执行select语句!
batch():执行批处理!- QueryRunner之更新
- 创建QueryRunner
- update()方法
int update(Connection con, String sql, Object… params)
public void fun1() throws SQLException {
QueryRunner qr = new QueryRunner();
String sql = "insert into user values(?,?,?)";
qr.update(JdbcUtils.getConnection(), sql, "u1", "zhangSan", "123");
}
- 还有另一种方式来使用QueryRunner
- 创建QueryRunner
构造器:QueryRunner(DataSource) - update()方法
int update(String sql, Object… params)
这种方式在创建QueryRunner时传递了连接池对象,那么在调用update()方法时就不用再传递Connection了。
public void fun2() throws SQLException {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
String sql = "insert into user values(?,?,?)";
qr.update(sql, "u1", "zhangSan", "123");
}
BaseServlet
- BaseServlet的作用
是让一个Servlet可以处理多种不同的请求。不同的请求调用Servlet的不同方法。我们写好了BaseServlet后,让其他Servlet继承BaseServlet,例如CustomerServlet继承BaseServlet,然后在CustomerServlet中提供add()、update()、delete()等方法,每个方法对应不同的请求。
- BaseServlet代码
public class BaseServlet extends HttpServlet {
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
res.setContentType("text/html;charset=utf-8");
// 例如:http://localhost:8080/demo1/xxx?m=add
String methodName = req.getParameter("method");
// 当没用指定要调用的方法时,那么默认请求的是execute()方法。
if(methodName == null || methodName.isEmpty()) {
methodName = "execute";
}
Class c = this.getClass();
//得到Class
try {
// 通过方法名称获取方法的反射对象
Method m = c.getMethod(methodName, HttpServletRequest.class,
HttpServletResponse.class);
String result = (String) m.invoke(this, req, res);
if(result != null && !result.isEmpty()) {
req.getRequestDispatcher(result).forward(req, res);
}
} catch (Exception e) {
throw new ServletException(e);
}
}
}