Jdbc
1 简单数据查询
@Test
public void select() throws Exception {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from student_table");
while (rs.next()) {
System.out.println(rs.getInt(1) + "\t" + rs.getString(2) + "\t" + rs.getString(3));
}
} finally {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
}
2 数据添加
使用PreparedStatement的好处:
1 PreparedStatement可以使用占位符,是预编译的. 批处理比Statement效率高,最大程度的提高性能。
JDBC驱动会发送一个网络请求到数据解析和优化这个查询. 而执行时会产生另一个网络请求. 在JDBC驱动中,减少网络通讯是最终的目的. 如果我的程序在运行期间只需要一次请求, 那么就使用Statement. 对于Statement, 同一个查询只会产生一次网络到数据库的通讯.当使用PreparedStatement池时, 如果一个查询很特殊, 并且不太会再次执行到, 那么可以使用Statement. 如果一个查询很少会被执行,但连接池中的Statement池可能被再次执行, 那么请使用PreparedStatement. 在不是Statement池的同样情况下, 请使用Statement.
2 提高代码的可读性和可维护性;
3 可以防止SQL注入
SQL注入指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。
Statement:
@Test
public void insertUseStatement() throws Exception {
long start = System.currentTimeMillis();
Connection conn = null;
Statement stmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
stmt = conn.createStatement();
for (int i = 0; i < 1000; i++) {
stmt.executeUpdate("insert into student_table values(null,'姓名" + i + "',1)");
}
System.out.println("使用Statement费时:" + (System.currentTimeMillis() - start));
} finally {
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
}
插入1000条数据的耗时:
使用Statement费时:67123
PreparedStatement:
@Test
public void insertUsePrepare() throws Exception {
long start = System.currentTimeMillis();
Connection conn = null;
PreparedStatement pstmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
pstmt = conn.prepareStatement("insert into student_table values(null,?,1)");
for (int i = 0; i < 1000; i++) {
pstmt.setString(1, "姓名" + i);
pstmt.executeUpdate();
}
System.out.println("使用PreparedStatement费时:" + (System.currentTimeMillis() - start));
} finally {
if (pstmt != null) {
pstmt.close();
}
if (conn != null) {
conn.close();
}
}
}
输出:
使用PreparedStatement费时:65633
3 批量数据添加
@Test
public void insertUseBatch() throws Exception {
long start = System.currentTimeMillis();
Connection conn = null;
Statement stmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
stmt = conn.createStatement();
for (int i = 0; i < 1000; i++) {
stmt.addBatch("insert into student_table values(null,'姓名" + i + "',1)");
if ((i + 1) % 300 == 0) {
stmt.executeBatch();
}
}
stmt.executeBatch();
System.out.println("使用Batch费时:" + (System.currentTimeMillis() - start));
} finally {
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
}
4 事务控制
@Test
public void insertInTransaction() throws Exception {
String[] sqls=new String[]{
"insert into student_table values(null,'aaa',1)",
"insert into student_table values(null,'bbb',1)",
"insert into student_table values(null,'ccc',1)",
"insert into student_table values(null,'ccc',1)"
};
Connection conn=null;
Statement stmt=null;
try {
Class.forName(driver);
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
conn.setAutoCommit(false);
stmt = conn.createStatement();
for (String sql : sqls) {
stmt.executeUpdate(sql);
}
conn.commit();
} finally {
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
}
5 存储过程调用
@Test
public void callProcedure() throws Exception {
Connection conn = null;
CallableStatement cstmt = null;
try {
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
// 使用Connection来创建一个CallableStatment对象
cstmt = conn.prepareCall("{call add_pro(?,?,?)}");
cstmt.setInt(1, 4);
cstmt.setInt(2, 5);
// 注册CallableStatement的第三个参数是int类型
cstmt.registerOutParameter(3, Types.INTEGER);
// 执行存储过程
cstmt.execute();
// 获取,并输出存储过程传出参数的值。
System.out.println("执行结果是: " + cstmt.getInt(3));
} finally {
if (cstmt != null) {
cstmt.close();
}
if (conn != null) {
conn.close();
}
}
}
6 元数据获取
public class DatabaseMetaDataTest {
private String driver;
private String url;
private String user;
private String pass;
Connection conn;
ResultSet rs;
public void initParam(String paramFile) throws Exception {
// 使用Properties类来加载属性文件
Properties props = new Properties();
props.load(new FileInputStream(paramFile));
driver = props.getProperty("driver");
url = props.getProperty("url");
user = props.getProperty("user");
pass = props.getProperty("pass");
}
public void info() throws Exception {
try {
// 加载驱动
Class.forName(driver);
// 获取数据库连接
conn = DriverManager.getConnection(url, user, pass);
// 获取的DatabaseMetaData对象
DatabaseMetaData dbmd = conn.getMetaData();
// 输出此数据库产品的名称和版本号
System.out.println(dbmd.getDatabaseProductName()+" "
+ dbmd.getDatabaseProductVersion());
// 获取此 JDBC 驱动程序的名称
System.out.println(dbmd.getDriverName()+dbmd.getDriverVersion());
// 获取MySQL支持的所有表类型
ResultSet rs = dbmd.getTableTypes();
System.out.println("----MySQL支持的表类型信息------");
printResultSet(rs);
// 获取当前数据库的全部数据表 获取可在给定类别中使用的表的描述。
// 仅返回与类别、模式、表名称和类型标准匹配的表描述。它们根据 TABLE_TYPE、TABLE_CAT、TABLE_SCHEM 和
// TABLE_NAME 进行排序。
/**
* TABLE_CAT String => 表类别(可为 null)
TABLE_SCHEM String => 表模式(可为 null)
TABLE_NAME String => 表名称
TABLE_TYPE String => 表类型。典型的类型是 "TABLE"、"VIEW"、"SYSTEM TABLE"、
"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"。
*/
rs = dbmd.getTables(null, null, "%", new String[] { "TABLE" });
System.out.println("----当前数据库里的数据表信息-----");
printResultSet(rs);
// 获取student_table表的主键
//表类别 表模式 表名称
rs = dbmd.getPrimaryKeys(null, null, "student_table");
System.out.println("----student_table表的主键信息-----");
printResultSet(rs);
// 获取当前数据库的全部存储过程 类别名称 模式名称的模式 过程名称模式
rs = dbmd.getProcedures(null, null, "%");
System.out.println("----当前数据库里的存储过程信息-----");
printResultSet(rs);
// 获取teacher_table表和student_table之间的外键约束
//父键表类别 模式 导出该键表的名称 类别 模式名称 导入该键标的名称
rs = dbmd.getCrossReference(null, null, "teacher_table", null,
null, "student_table");
System.out.println("----teacher_table表和student_table之间的外键约束-----");
printResultSet(rs);
// 获取student_table表的全部数据列 表类别 表模式 表明称 列名称
rs = dbmd.getColumns(null, null, "student_table", "%");
System.out.println("----student_table表的全部数据列-----");
printResultSet(rs);
}
// 使用finally块来关闭数据库资源
finally {
if (rs != null) {
rs.close();
}
if (conn != null) {
conn.close();
}
}
}
public void printResultSet(ResultSet rs) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
// 打印ResultSet的所有列标题
for (int i = 0; i < rsmd.getColumnCount(); i++) {
System.out.print(rsmd.getColumnName(i + 1) + "\t");
}
System.out.print("\n");
// 打印ResultSet里的全部数据
while (rs.next()) {
for (int i = 0; i < rsmd.getColumnCount(); i++) {
System.out.print(rs.getString(i + 1) + "\t");
}
System.out.print("\n");
}
rs.close();
}
public static void main(String[] args) throws Exception {
DatabaseMetaDataTest dt = new DatabaseMetaDataTest();
dt.initParam("mysql.ini");
dt.info();
}
}