JDBC操作数据库

一、JDBC的概念

JDBC:JavaDataBaseConnection:通过java代码操作数据库。可以把JDBC看成一个操作Mysql的一个客户端。
JDBC使用步骤:
1、加载mysql的驱动类:mysql-connector-java-5.1.7-bin.jar。
2、建立数据库与JAVA之间的连接:DriverManager.getConnection(url, user, password);url是数据库连接地址:jdbc:mysql://localhost:3306/数据库名。此处连得是本机。user是用户名,password是数据库登录密码。
3、通过Connection对象创建Statement对象,conn.createStatement();
4、通过Statement发送SQL语句,executeUpdate():只能发送DML语句,executeQuery();可以执行DQL语句。

代码如下:

public class JDBCDemo1 {
	//数据库连接地址:
	//jdbc:mysql://mysql's ip:3306/数据库名
	private static String url 
			= "jdbc:mysql://127.0.0.1:3306/ph";
	private static String user = "j180703";
	private static String password = "123456";
	//驱动类名
	private static String driverClassName 
			= "com.mysql.jdbc.Driver";
	/**
	 * 创建数据库连接,并返回该连接对象
	 * @return 连接对象
	 */
	public static Connection getConnection(){
		//DriverManager负责安装数据库驱动
		Connection conn = null;
		try {
			//加载com.mysql.jdbc.Driver类到JVM
			Class.forName(driverClassName);
			//通过DriverManager创建数据库连接
			conn = DriverManager.getConnection(
					url, user, password);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}
	
	/**
	 * 向学生表插入一行记录,使用DML语句
	 * @param args
	 */
	public static void insertDemo(){
		try {
			//1.获取连接
			Connection conn = getConnection();
			//2.通过Connection对象创建Statement对象
			Statement stmt = conn.createStatement();
			//3.编写sql语句
			String sql = "insert into t_student " + 
				"values(null,'phooxx2b','男',28," + 
				"'2018-08-01','xxoo@163.com',1)";
			//4.通过Statement发送SQL
			//executeUpdate():只能发送DML语句
			int result = stmt.executeUpdate(sql);
			if(result!=1){
				System.out.println("插入失败!");
			}else{
				System.out.println("插入成功!");
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 查询学生表中的所有记录,使用的是DQL语句
	 */
	public static void queryDemo(){
		
		try {
			//1.获取连接
			Connection conn = getConnection();
			//2.通过Connection对象创建Statement对象
			Statement stmt = conn.createStatement();
			//3.编写sql
			String sql = "select * from t_student";
			//4.发送Sql
			//发送DQL使用executeQuery(),返回值为ResultSet
			//ResultSet结果集,该对象封装了查询结果
			//ResultSet有行有列,它就是虚拟表
			ResultSet rs = stmt.executeQuery(sql);
			//取出ResultSet中的结果:
			//一次取一行,循环去取,直到取完
			//rs.next():判断是否有下一行,如果有直接取出
			//相当于迭代器的hasNext()+next()
			while(rs.next()){
				//next()一次就取出了一行
				//取一行中的各列值:
				System.out.println(rs.getInt("student_id"));
				System.out.println(rs.getString("student_name"));
				System.out.println(rs.getString("sex"));
				System.out.println("-----------");
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

Statement的缺点:
1、拼写sql容易出错
2、不能防止sql注入
因此开发中我们常用PreparedStatement来执行sql语句。(sql注入不懂的可以上网查查,在这里就不在细讲。)

使用PreparedStatement来进行数据库操作
public class DBUtil {
		private static String url;
		private static String user;
		private static String password;
		//驱动类名
		private static String driverClassName ;
		//static代码块会在类被JVM加载是立即执行
		//读取db.properties文件,并给静态属性赋值
		static{
			//1、读取db.properties文件
			//读取src以及同级目录下的文件
			//1.1getClassLoader()获取config的classloader
			//获取IO流
			InputStream in = DBUtil.class.getClassLoader().
							getResourceAsStream("db.properties");
			//1.2创建properties对象
			//专门读取.properties文件工具类
			Properties prop = new Properties();
			try {
				//加载输入流
				prop.load(in);
			} catch (IOException e) {
				e.printStackTrace();
			}
			//2、给静态属性赋值
			url = prop.getProperty("jdbc.url");
			user = prop.getProperty("jdbc.user");
			password = prop.getProperty("jdbc.password");
			driverClassName = prop.getProperty("jdbc.driverClassName");
		}
		
		/**
		 * 创建数据库连接,并返回该连接对象
		 * @return 连接对象
		 */
		public static Connection getConnection(){
			//DriverManager负责安装数据库驱动
			Connection conn = null;
			try {
				//加载com.mysql.jdbc.Driver类到JVM
				Class.forName(driverClassName);
				//通过DriverManager创建数据库连接
				conn = DriverManager.getConnection(
						url, user, password);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return conn;
		}
		
		/**
		 * general:通用
		 * 封装一个通用增删改方法
		 * @param sql Object... params:占位符:
		 *Object... 表示参数个数不确定,但必须放在最后一个参数位置
		 *相当于一个数组
		 */
		public static int generalUpadate(String sql,Object... params){
			int result = 0;
			Connection conn = null;
			PreparedStatement pstmt = null;
			try {
				conn = getConnection();
				//此处执行sql语句,但占位符处值为空
				pstmt = conn.prepareStatement(sql);
				//给sql中的占位符赋值
				if(params!=null){
					for (int i = 0; i < params.length; i++) {
						pstmt.setObject(i+1, params[i]);
					}
				}
				//将赋值过的占位符值传给sql语句
				result = pstmt.executeUpdate();
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				closeAll(conn,pstmt,null);
			}
			return result;
		}
		
		/**
		 * 通用查询,可以查询任意表,可以把查询结果封装成任意对象
		 * Java类的属性名要和数据库的列名一致
		 * 因为是通过列名反射得到的属性名
		 * @param <X> 占位符,声明泛型
		 * @param cls 要封装对象的类对象
		 * @param sql 查询语句
		 * @param params sql语句中的占位符值:Object... 
		 */
		public static <X> List<X>  generalQuery(Class<X> cls,String sql,Object...params){
			List<X> list = new ArrayList<>();
			Connection conn = null;
			PreparedStatement pstmt = null;
			ResultSet rs = null;
			try {
				conn = getConnection();
				pstmt = conn.prepareStatement(sql);
				//给sql中占位符赋值
				if(params!=null){
					for (int i = 0; i < params.length; i++) {
						pstmt.setObject(i+1, params[i]);
					}
				}
				//将占位符的值传过去
				rs = pstmt.executeQuery();
				//如何获取列名
				//ResultSetMetaData:封装了列的名和列的总数
				ResultSetMetaData md = rs.getMetaData();
				//获取列的总数
				int columnCount = md.getColumnCount();
				//md.getColumnName(column):通过列号获取列名
				X x = null;
				String columnName = null;
				while(rs.next()){
					//一行记录对应一个对象
					x = cls.newInstance();
					//给对象属性赋值
					//获取列名,为反射做准备
					//一行有很多列,列号从一开始
					for (int i = 1; i <= columnCount; i++) {
						columnName = md.getColumnName(i);
						//取出一个列名,反射得到一个属性
						try {
							//1、获取父类类对象
							Class<?> superCls = cls.getSuperclass();
							if(superCls == Object.class){
								//如果一个类无直接父类,那么该类属性全在本类中
								throw new NoSuchFieldException();
							}
							Field superField = superCls.getDeclaredField(columnName);
							//无异常表示属性属于父类,给属性赋值
							superField.setAccessible(true);
							superField.set(x, rs.getObject(i));
							
						} catch (NoSuchFieldException e) {
							// TODO: handle exception
						//	e.printStackTrace();
							//抛出异常属性在子类中
							Field childField = cls.getDeclaredField(columnName);
							childField.setAccessible(true);
							childField.set(x, rs.getObject(columnName));
						}
					}
					//循环一次结束讲对象加到集合中
					list.add(x);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				closeAll(conn, pstmt, rs);
			}
			return list;
		}
		
		/**
		 * 关闭资源
		 * Connection,Statement,ResultSet
		 */
		public static void closeAll(Connection conn,Statement stmt,ResultSet rs){
			try {
				//先开的后关
				if(rs!=null){
					rs.close();
				}
				if(stmt!=null){
					stmt.close();
				}
				if(conn!=null){
					conn.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
			System.out.println(getConnection());
		}
}

版权声明:本文为ajhblogs529原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ajhblogs529/p/9538841.html