The total number of basic concepts of JDBC (including Spring templates and database connection pools)

JDBC

  1. Basic concepts of JDBC
  2. Quick start
  3. Detailed explanation of each interface and class in JDBC

Basic concepts of JDBC

1. 概念:Java Database Connectivity  Java -> 数据库连接(Java语言操作数据库)
	* JDBC的本质,由官方定义了一套操作所有关系型数据库的规则,即接口。
	* 各个数据库厂商提体的具体的实现类,这个具体的实现类被称为数据库驱动。
2.快速入门
		* 步骤:
				1.导入驱动Java包
					1.1复制jar到项目的lib目录下
					1.2右键-->Add As Library
				2.注册驱动
					2.1 Class.forname("com.mysql.jdbc.Driver");//注册
				3.获取数据库的连接对象(Connection对象)
				4.获取sql语句的执行对象(statement)
				5.执行sql,接受返回结果
				6.处理返回结果
				7.释放资源
			
		*代码实现:public static void main(String[] args) throws SQLException {  
			    //导入驱动的jar包  
				  Statement statm = null;  
				  Connection conn = null;  
				 try {  
				        //2.注册驱动包  
				  Class.forName("com.mysql.jdbc.Driver");  
				  
				  //3.获取连接  
				  conn = DriverManager.getConnection("jdbc:mysql://localhost:3307/mysql2","root","123456");  
				  
				  //4.定义sql语句  
				  String sql = "update user set loginName='zhangsan',lologinPwd='123456' where loginName = 'zhangsan'";  
				  
				  //5.获取执行sql对象的statement  
				  statm = conn.createStatement();  
				  
				  //6.执行sql  
				  statm.executeUpdate(sql);  
				  
				  } catch (ClassNotFoundException e) {  
				        e.printStackTrace();  
				  } finally {  
				        //7.释放资源  
				  if(statm != null){  
				            statm.close();  
				  }  
				        if(conn != null){  
				            conn.close();  
				  }  
				    }  
				}
3.详解各个对象
	3.1	DriverManager(类):驱动管理对象(告诉程序性我们要使用,哪个数据库的驱动包)
		*功能:
			1.注册驱动->static void registerDriver(Driver driver)->注册-->给定的驱动程序 DriverManager.
						Class.forName("com.mysql.jdbc.Driver");这个反射获取了com.mysql.jdbc.Driver这个路劲下的Driver类,并且在Driver类中的静态代码块中执行registerDriver方法,注册了驱动信息。
			#在Driver类中包含了一个静态代码块,在没有对象的前提下也可以执行,
					static {

					try {

								java.sql.DriverManager.registerDriver(new  Driver());   //这个就是利用放射调用Driver类的时候,这里的静态代码区会被执行,也就是执行了这个方法注册了驱动

								} catch (SQLException  E) {

								throw  new  RuntimeException("Can't register driver!");

					}

					}

	注意:mysql 5之后的驱动jar包可以忽略。
				
		
			2.获取数据库连接对象
				*方法:->Driver.getConnection(String url,String user, String password);
				*参数:
					*url;指定 连接的路径
						*语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
							 *例子:jdbc:mysql://localhost:3307//mysql2
							 *细节:当连接的是本机的mysql服务器,并且mysql服务器默认端口是3306的时候,则url可以简写为jdbc:mysql:///mysql2
	3.2	Connection(接口):	数据库连接对象
		*功能:
			1.获取执行sql的对象(Statement,PrePareStatement)
				    *Statement createStatement()
				    *PreparedStatement prepareStatement(String sql);
			2.管理事物:
					*开启事物
							void setAutoCommit(boolean autoCommit);当传入的参数为false的时候,,关闭自动提交,就是开启事物。
					*提交事物
							void commit();
					*回滚事物	    
							void rollback();
	3.3 Statement(接口,执行静态的sql语句,静态的sql):执行sql的对象
			1.执行sql
				*boolean execute(String sql):可以执行任意的sql  	@了解
				*int executeUpdate(String sql):执行dml(insert,update,delete)语句;ddl(create,alter,drop)语句  @ddl语句一般在sql中执行,不在java中执行。
					返回值的是,sql语句影响的行数(具体改变了多少行),用于判断是否执行成功。
				*ResultSet executeQuery(String sql):执行dql(select)语句,
					返回值:返回结果集对象(ResultSet)
			2.练习:	
				1.account表 添加一条记录
				2.account表 修改记录
				3.account表 删除一条记录		
	3.4 ResultSet:结果集对象,对返回集进行处理
				*boolean next():游标向下移动一行(每执行一次next(),光标向下移动一行,移动后的那一行有数据返回true,否则返回false,类似迭代器)
				*xxx getxxx(参数):获取数据
					*返回值:xxx是数据类型, 如:String getString()
					*参数:(有重载的方法)
						1. int类型参数:代表列的编号,从1开始的(特殊)  如:getString(1)
						2. String类型参数:代表列的字段名。 如:getInt("id");
					*注意:
						*使用步骤
							1.游标向下移动一行
							2.判断是否有数据(关键)
							3.获取数据
					*练习:
						*查询emp表的数据,将其封装为对象,然后装载集合,然后打印,返回。(提示一张表可以类比成一个类,一条记录类比成一个对象)		
							1.定义一个emp类
							2.定义一个方法public List<emp> findAll();
							3.实现方法 select * from emp;
	3.5 PreparedStatement(接口,执行预编译的sql语句,动态的sql):执行sql对象,更加强大,继承自statement
				*由于在拼接sql时,有一些sql的关键字参与字符串的拼接,会造成安全问题
				 1.为解决sql注入问题,提供了PreparedStatement对象来解决
				 2.预编译的sql:参数使用?作为占位符
				 3.步骤:
						 1.导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
						 2.注册驱动
						 3.获取数据库连接对象Connection
						 4.定义sql
							  *注意:sql的参数使用:?作为占位符。如:select * from user where username = ? and password = ?;
						 5.获取sql执行对象(获取的是PreparedStatement对象,这个与createdStatement()不同,prepareStatement(String sql)这个方法需要将带?的预编译的sql字符串作为参数传入)
						 6.给?赋值
							 使用prepareStatement下的方法,setxxx(参数1,参数2)
								*参数1:赋值第一个?
								*参数2:赋值第二个?
						 7.执行sql,接受返回结果,不需要在传入sql语句
						 8.处理结果
						 9.释放资源
				*注意:后期都会使用PerparedStatement对象来完成增删改查的所有操作
						1.可以防止sql注入
						2.效率更高		 
4.抽取JDBC的工具类
	*目的:简化书写
	*分析:
			1.抽取一个方法获取连接对象 
			2.注册一个方法获取连接对象
					*需求:	想要动态配置ip,端口和数据库,又不想要传参
				    *解决方案:使用配置文件
						jdbc.properties
							url=
							user=
							password=
						
						*从jdbc.properties文件中相关字符串的办法,通过Properties对象的load(new DileReader("路径"))方法
							路径的方法可以是动态的获取路径信息,利用类中本身含有的方法获取ClassLoader的对象,再利用ClassLoader类的方法getResource("文件名字"),返回一个URL对象;再利用URL对象下的getPath(),返回路径的字符串。
							*`static{  
							    try {  
										        //读取资源文件,获取值  
									  //1.创建一个properties集合类  
									  Properties pro = new Properties();  
									  //获取src路径下的文件方式--->ClassLoader类加载器  
									  ClassLoader classLoader = JDBCUtils.class.getClassLoader();  
									  URL res = classLoader.getResource("jdbc.properties");  
									  String path = res.getPath();  
									  //2.加载文件  
									  //pro.load(new FileReader("./src/jdbc.properties"));  
									  pro.load(new FileReader(path));  
									  url = pro.getProperty("url");  
									  user = pro.getProperty("user");  
									  password = pro.getProperty("password");  
									  driver = pro.getProperty("driver");  
									  } catch (IOException e) {  
									        e.printStackTrace();  
									  }  
									}`	
					
			*练习:
				*需求:
					1.通过键盘录入用户名和密码
					2.判断用户是否登录成功	
						*select * from user where username = '+userName+' and password = '+password+';
						*如果这个sql有查询结果,则成功,反之则失败。
							
				*步骤
						1.创建登录表 create table user();
						2.将登录界面打包封装成一个方法
						3.利用工具类,开始注册创建驱动和获得连接 
								*Connection conn = JDBCUtil.getConnection();
						4.写sql命令
						5.获取sql命令的执行对象,Statement
						6.执行命令,获取ResultSet结果集,
						7.返回判断结果
											
			   *程序bug
					   *sql注入(在拼接sql时,有一些sql的关键字参与字符串的拼接,会造成安全问题)
						   1.输入用户随便,输入的密码:a' or 'a' = 'a
						   2.sql: 随便输入用户名:faaf, 得到的sql语句:select * from user where username = 'faaf' and password = 'a' or 'a' = 'a'(这里由于字符串在拼接的时候出现了问题)
								  解释:目的是将a' or 'a' ='a 视为一个字符串来进行判断 ,
										  但是在实际执行的时候出现了 数据库将其视为了 
										  username = 'faaf' 
										  and
										  password = 'a'
										  or
										  'a' = 'a',三种逻辑态的拼接,由于and的优先级更高,先执行and,右边为false ,但是 or右边为恒等式为true,最后结果为true ---> 由于where的右边恒为true,也就select在执行比对时每一行记录都不会被筛除,select会输出所有记录,这种就被称为sql注入;
						   3.解决方法:使用perpareStatement
5.JDBC控制事物
		 1.事物:一个包含多个不做的业务操作。如果这个业务操作被事物管理,则这多个事物要么同时成功,要么同时失败。
		 2.操作:
			 1.开始事物
			 2.提交事物
			 3.回滚事物
		
		 3.使用Connect对象来管理事物
			 *开启事物: setAutoCommit(boolean autoCommit) ,将传入参数false代表事物开启(自动提交关闭)   在执行sql命令之前开启事物
			 *提交事物:commit(); 顺利完成commit
			 *回滚事物:rollback(); 出现异常回滚,在catch{}中使用rollback()

6.数据库连接池--->因为连接(Connection)建立在try  catch中会被频繁的删除,在频繁的建立连接会拖延系统的时间,因此引入了数据库池。
		*概念:其实就是一个容器,存放数据库连接的容器;当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库的时候,从容器中获取连接对象,用户访问完后,将会把连接对象归还给容器。
			  例子:这下所有的服务员被一家公司集中管理,餐馆需要服务员时直接去公司申请,不在需要自己去去找服务员(高效),这样节约了自己找人的成本,因为公司集中化管理给的价格也更低(节约了资源)
		*好处,优点:
			1.节约系统的资源(集中管理连接对象,更资源分配更均匀)
			2.高效(不需要向底层申请,节约时间,申请和返回不需要底层的参加)
		*实现
			1.标准的接口:DataSource	(java.sql包内的)
				1.方法;
					*获取连接:getConnection()---->获取连接
					*归还连接:如果连接对象Connetion是从连接池中获取的,那么调用的不是关闭连接,而是归还连接到容器中,他们名字都相同,意义不同;调用Connection.close(); 
			2.一般我们不去实现它,有数据库厂商来实现
				1.C3P0:数据库连接池技术
				2.Druid:数据库连接池实现技术,有阿里巴巴提供。
			3.C3P0:数据库连接池技术
					*步骤
						 1.导入jar包(两个) C3P0-0.9.2.jar and  mchange-commons-java-0.2.12.jar还有导入mysql的驱动包			 
						 2.	定义配置文件:
								*名称:c3p0.properties 或者 c3p0-config.xml(名称是固定了的,其自带的有)
								*路径:ClassPath路径下(类路径下),直接将文件放在src目录下
						 3.创建核心对象,数据库连接池对象ComboPooledDataSource
						 4.获取连接:getConnection
			 4.Druid:数据库连接池,由阿里巴巴提供
					1.步骤:
						1.导入jar包 druid-1.0.9.jar
						2.定义配置文件
							*是properties形式的
							*可以叫任意名称,放置在任意位置
						3.加载配置文件,properties	
						4.获取数据库的连接池对象;通过工厂类来获取 DruidDataSourceFactory
						5.获取连接:getConnection();
					2.定义一个工具类
					    1.定义一个类 JDBCUtils
					    2.使用静态代码块来加载配置文件properties,初始化连接池对象。
					    3.提供的方法
						    1.获取连接方法:通过数据库连接池获取连接
						    2.提供一个获取连接池对象的方法
							3.释放资源			 
7.spring JDBC: JDBC Template模板
	##spring 框架对JDBC的简单封装,提供了JDBCTemplate对象简化JDBC的开发
	*步骤
		1.导入jar包
		2.创建JDBCTemplate对象,依赖于数据源DataSource对象
			*JDBCTemplate template = new JDBCTemplate(ds);
		3.调用JDBCTemplate对象的方法来完成操作
			*update()-->增删改语句,使用的是prepareStatement的sql 格式,这个例如,update(sql,第一个?的赋值 , 第二个?的赋值,.......)
			*queryForMap():查询结果集封装成map集合
			*queryForList():查询结果封装为List集合
			*query():查询结果,将结果封装为JavaBean对象
				*query的参数:RowMapper
					*一般我们在使用BeanPropertyRowMapper<类型>(类型的字节码对象)(实现了RowMapper接口),因此可以使用他们来实现接口回调来完成数据的自动封装
					*new BeanPropertyRowMapper<类型>(类型的字节码对象)
			*queryForObject:查询结果,将结果封装为Object对象	
		4.练习
			*需求
				1.查询所有记录将其封装为List集合
						*返回得到记录的集合,一个map获取一条记录,所以这个是记录的集合,将map作为排队元素 List<Map<String,Object>> list = template.queryForList(sql,......);
				2.查询id为1的记录所有记录将其封装为Map集合  返回记录只能是一条记录,否则会报错;因为字段名当成map的键,记录当成值。     
						*一条记录封装成一个map集合(期望一条记录)
				3.查询所有记录,将其封装为对象Emp对象的List集合
					*使用query()方法(期间会使用到接口参数,就需要使用内部类来重写接口中的方法),来使用Emp来记录信息,列成List集合类返回。
							(****重点****)其中,如果自己使用的是自定类的时候,使用基本数据类型是不能接受数据库表记录中的NULL的,因此在读取值中含有NULL的时候,就是使用引用数据类型的,不使用基本数据类型  比如 double-->Double ,int--->Integer ,boolean--->Boolean 可以接受为NULL的返回值
					*案例代码:		
					//使用内部匿名类进行对自己封装的类的初始化  
	  List<Emp>list = template.query(sql, new RowMapper<Emp>(){  
	  
	        @Override  
	  public Emp mapRow(ResultSet resultSet, int i) throws SQLException {  
	            Emp emp = new Emp();  
	  int empno = resultSet.getInt("empno");  
	  String ename = resultSet.getString("empno");  
	              
	  String job = resultSet.getString("job");  
	  int mgr = resultSet.getInt("mgr");  
	  Date hiredate = resultSet.getDate("hiredate");  
	  double sal = resultSet.getDouble("sal");  
	  double comm = resultSet.getDouble("comm");  
	  int deptno = resultSet.getInt("deptno");  
	  
	  emp.setEmonp(empno);  
	  emp.setEname(ename);  
	  emp.setJob(job);  
	  emp.setMgr(mgr);  
	  emp.setHiredate(hiredate);  
	  emp.setSal(sal);  
	  emp.setComm(comm);  
	  emp.setDeptno(deptno);  
	 return emp;  
	  }  
	    });  //内部匿名类的写法  
	  Iterator<Emp> iterator = list.iterator();  
	 while (iterator.hasNext()){  
	        System.out.println(iterator.next());  
	  }  
	}
				
			4.查询总记录数(就是利用select查询得到的是一个数,不是一个记录的使用使用的方法)
				*Long long = template.queryForObject(sql,Long.class(long的字节码对象))
			
				*补充知识:注解@Test,可以使用其注释部分单独运行,测试	

Guess you like

Origin blog.csdn.net/qq_45788043/article/details/111599889