Day39
*java制定了一套统一的接口来连接不同的数据库,各大数据库厂商按照这个接口实现了连接各自数据库的方案(如下图):
*使用JDBC执行DQL语句,并将结果保存在一个集合里面
public class TestJDBCtoList {
public static void main(String[] args) {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/nz2001";
String name = "root";
String pass = "123";
con = DriverManager.getConnection(url, name, pass);
String sql = "SELECT uid id,uname,upass FROM USER";
ps = con.prepareStatement(sql);
//·使用executeQuery方法执行DQL语句并得到一个结果集:ResultSet
rs = ps.executeQuery();
List<User> user = new ArrayList<User>();
//·next方法:判断有没有下一行,如果有则返回true,并且指针指向下一行(第一次的时候指针指向的是表头)
//·表头指的就是显示别名的那一行
while(rs.next()) {
//·get方法里面的字符串都是别名 而不是字段名
User u = new User(rs.getInt("id"), rs.getString("uname"), rs.getString("upass"));
user.add(u);
}
//·遍历打印
for (User u : user) {
System.out.println(u);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//·关闭
try {
if(null != rs) {
rs.close();
}
if(null != ps) {
ps.close();
}
if(null != con) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public class User {
private int uid;
private String uname;
private String upass;
//user实体类,构造方法,getset方法,tostring方法略
}
*使用DQL语句进行登录逻辑:(对上面进行更改)
I. 首先需要更改sql语句,这里也可以将全部记录查询到再筛选,但是效率很低而且代码过于繁琐。
String sql = "select uid,uname,upass from user where uname=? and upass=?";
II. 添加上控制台录入
Scanner input = new Scanner(System.in);
System.out.println("请输入用户名");
String username = input.nextLine();
System.out.println("请输入密码");
String password = input.nextLine();
input.close();
III. 修改预处理语句,将控制台接受到的用户名和密码加入到sql语句中
ps.setString(1, username);
ps.setString(2, password);
IV. 使用if语句判断是否得到查询结果(因为不会有两条用户名和密码一模一样的数据,这里的查询结果只有两种情况:查到结果和没查到结果)
if (rs.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}
*批处理(需要做批处理操作时,url需要加上?rewriteBatchedStatements=true,才是真正的批处理。MySQL JDBC驱动在默认情况下会无视executeBatch()语句,把我们期望批量执行的一组sql语句拆散,一条一条地发给MySQL数据库,批量插入实际上是单条插入,直接造成较低的性能。只有把rewriteBatchedStatements参数置为true, 驱动才会帮你批量执行SQL)
I. 对不同的sql进行批处理
1)写几个不同的DML语句
String sql1 = "INSERT INTO USER(uname,upass) VALUES('zhangsan',777)";
String sql2 = "UPDATE USER SET upass=789 WHERE uname='tom'";
String sql3 = "DELETE FROM USER WHERE uid=1";
2)执行并清空批处理
//·执行批处理,每一条sql语句返回一个int值(数据库受影响行数),并保存在一个int数组中然后返回
int[] result = st.executeBatch();//·打印这个result数组的结果是1 1 1
st.clearBatch();//·清空批处理
II. 对相同的sql进行批处理
1)写一个带有占位符的sql语句
String sql = "insert into user(uname,upass) values(?,?)";
2)使用循环进行预处理,然后添加进批处理中
for (int i = 0; i < 100; i++) {
ps.setString(1, "jack"+i);
ps.setString(2, "pass"+i);
ps.addBatch();
}
3)执行并清空
ps.executeBatch();
ps.clearBatch();
*DBUtils封装(每次使用JDBC连接数据库时,都会产生大量的重复代码,所以对连接数据库的一些必要操作进行封装)
I. 因为加载驱动只需要进行一次,所以写在静态代码块中;由于是工具类,属性都是静态的,所以可以在静态代码块中对静态属性进行初始化。将三个字符串(url,user,password)信息封装到jdbc.properties,并将编译后的文件添加至编译后文件夹(bin文件夹)的根目录。
/*
* ·DBUtil.class.getClassLoader()得到一个类加载器对象
* ·可以理解为bin下面的文件都归这个类加载器管理,
* ·再用getResourceAsStream方法获得一个对jdbc.properties文件的输入流
*/
InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties p = new Properties();
p.load(is);
url = p.getProperty("url");
user = p.getProperty("user");
pass = p.getProperty("pass");
//·加载驱动
Class.forName("com.mysql.jdbc.Driver");
II. 获取连接
public static Connection getConnection() {
try {
return DriverManager.getConnection(url, user, pass);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
III. 关闭连接
public static void close(Connection con, PreparedStatement ps, ResultSet rs) {
closeRs(rs);
closePs(ps);
closeCon(con);
}
private static void closeRs(ResultSet rs) {
if(null != rs) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static void closePs(PreparedStatement ps) {
if(null != ps) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private static void closeCon(Connection con) {
if(null != con) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
*对统一的DML语句进行封装:使用object的可变长参数(多态的应用)
public static boolean executeDML(String sql,Object... params) throws SQLException {
//·使用封装好的工具类获取连接
Connection con = DBUtil.getConnection();
//·获取预处理对象
PreparedStatement ps = con.prepareStatement(sql);
//·设置参数
setParams(ps,params);
//·大于0则表示执行成功
return ps.executeUpdate() > 0;
}
private static void setParams(PreparedStatement ps, Object... params) throws SQLException {
if(params != null) {
for (int i = 0; i < params.length; i++) {
//·对ps对象进行循环设置参数
ps.setObject(i, params[i]);
}
}
}
*补充知识:查询表的元数据(有哪些列,列名,一共有多少列 等等)
public static void main(String[] args) throws SQLException {
Connection con = DBUtil.getConnection();
String sql = "SELECT pid,pname,page FROM person";
PreparedStatement ps = con.prepareStatement(sql);
//·获取表的元数据对象,里面封装了表的所有元数据
ResultSetMetaData rm = ps.getMetaData();
//·getColumnCount获取列的个数
for (int i = 0; i < rm.getColumnCount(); i++) {
System.out.println("列名:"+rm.getColumnName(i+1)+",别名:"+rm.getColumnLabel(i+1)
+",数据库中的类型:"+rm.getColumnTypeName(i+1)+",java中的类型 "+rm.getColumnClassName(i+1));
}
}