一.环境配置(基于MySQL数据库)

 

 1.下载MySQL数据库

 2.下载安装 Navicat,破解方法去吾爱破解网站查询

   第一次连接mysql时可能会出现错误,可能是因为二者对密码的编码方法不一致,可通过在帮助中升级更新Navicat来解决

 3.下载JDBC jar包  mysql-connector-java-version.jar

   注意这里要说明一下JDBC jar包存放的位置:

    如果是Java项目:

Eclipse项目中导入该jar包,方法:右击项目→构建路径→配置构建路径→add external jar

    如果是Web项目:

  eclipse配置的tomcat默认发布项目不会部署到tomcat的安装目录去,所以JDBC jar包要手动复制到Web项目中的WebContent / WEB-INF / lib文件夹下

    如果是Tomcat导包(表示服务器可能要用到数据库,例如数据源):

如果是MyEclipse集成Tomcat,显然是要用“右键项目 -> Properties -> Java Build Path -> 右侧选项卡选择Libraries -> Add JARs...”。
如果是非集成Tomcat,你必须把驱动程序包复制粘贴在Tomcat根目录“common\lib”文件夹下。

二.JDBC技术简介

  JDBC(Java Data Base Connectivity)是Java程序与数据库系统通信的标准API,它定义在JDK的API中,通过JDBC技术,Java程序可方便地与各种数据库交互。

1.JDBC连接数据库的过程:

  

    在JDK中,不包含数据库的驱动程序,使用JDBC操作数据库,需要事先下载数据库厂商提供的驱动包。

  1.注册数据库驱动

    连接数据库之前,需要将数据库厂商提供的数据库驱动类注册到JDBC的驱动管理器,通常情况是通过数据库驱动类加载到JVM来实现的。

Class.forName("com.mysql.jdbc.Driver"); //最新更改为com.mysql.cj.jdbc.Driver

  2.构建数据库连接URL

    这个URL由数据库厂商来定,但符合格式“JDBC协议+IP地址或域名+端口+数据库名称”,比如MySQL的URL是“jdbc:mysql://localhost:3306/test”。

   3.获取Connection对象

    在完成注册和构建URL后,就可以通过驱动管理器来获取数据库连接Connection,Connection对象是JDBC封装的数据库连接对象,只有创建此对象后,才能对数据进行相关操作。

DriverManager.getConnection(url, username, password);//URL, 数据库用户名, 密码

测试实例:

package Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException; public class testJDBC { public static void main(String[] args) {
// TODO 自动生成的方法存根
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";
          //由于二者的字符编码方式可能不一致,故统一编码
String username = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url, username, password);
if (connection != null) {
System.out.println("数据库连接成功!");
connection.close();
}
else {
System.out.println("数据库连接失败!");
}
}catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e) {
e.printStackTrace();
}
}
}

2.JDBC API

  

1.Connection接口

  Connection接口位于java.sql包中,是与特定数据库的连接会话,只有获得特定数据库的连接对象,才能访问数据库,操作数据库中的数据表、视图和存储过程等,Connection接口的常用方法声明:

方法声明
说明
void close() throws SQLException   
立即释放Connection对象的数据库连接占用的JDBC资源,在操作完数据库后,应立即调用此方法
void commit() throws SQLException  
提交事务,并释放Connection对象当前持有的所有数据库锁。当事务被设置为手动提交模式时,需要调用该方法提交事务。

2.DriverManager类

  DriverManager类主要作用于用户及驱动程序之间,它是JDBC中的管理层,通过DriverManager类可以管理数据库厂商提供的驱动程序,并建立应用程序与数据库之间的连接。

  

3.Statement接口

  Statement接口提供了执行语句和获取查询结果的基本方法。

  

4.PreparedStatement接口

  实际开发中,SQL语句往往需要将程序中的变量做查询条件参数等,而使用Statement接口进行操作会过于繁琐,而且存在安全方面的缺陷。PreparedStatement接口继承于Statement接口,而且对带有参数SQL语句的操作执行进行了扩展。应用于PreParedStatement接口中的SQL语句,可以使用占位符“?”来代替SQL语句中的参数,然后再对其赋值。最好使用该接口,不仅可以提高SQL执行效率,而且还可以避免SQL语句的注入式攻击。

  

5.ResultSet接口

  执行SQL语句的查询结果会返回查询的结果集,而Result接口封装了该结果集。Result还提供了光标的功能,通过光标可以自由定位到某一行中的数据。

三.JDBC操作数据库

1.添加数据

  通过JDBC向数据库添加数据,可以使用INSERT语句实现插入数据的SQL语句,对应SQL语句中的参数可以使用占位符“?”代替,然后通过PreparedStatement对其赋值并执行SQL。

  实例:建立一个学生信息数据库,通过JDBC向其添加数据。

  1.首先在Navicat中创建名为student的数据库,创建student_info表

  2.创建名为Student的类,来封装学生对象信息

package com;

import java.io.Serializable;

public class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = -7421230515641293748L;
private int id;
private String name;
private String sex;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id=id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex=sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age=age;
}
}

  3.创建index.jsp页面,用于提交添加学生信息的表单。

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="AddStudent.jsp" method="post" onsubmit="return check(this)">
<table align="center" width="450">
<tr>
<td align="center" colspan="2">
<h2>添加学生信息</h2><hr>
</td>
</tr>
<tr>
<td align="center">学号:</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td align="center">姓名</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td align="center">性别</td>
<td><input type="text" name="sex"></td>
</tr>
<tr>
<td align="center">年龄</td>
<td><input type="text" name="age"></td>
</tr>
<tr>
<td align="center" colspan="2">
<input type="submit" value="添加">
</td>
</tr>
</table>
</form>
</body>
</html>

  4.创建AddStudent.jsp页面,用于对添加学生信息的请求处理,通过JDBC提交到数据库。

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="com.Student"%>
<%@ page import="java.sql.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%request.setCharacterEncoding("UTF-8"); %>
<jsp:useBean id="students" class="com.Student">
<jsp:setProperty property="*" name="students"/>
</jsp:useBean>
<%
try{
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";
String username = "root";
String password = "123456";
Connection conn= DriverManager.getConnection(url, username, password);
String sql="insert into student_info(id,name,sex,age) values(?,?,?,?)";
PreparedStatement ps=conn.prepareStatement(sql);
//使用PreparedStatement对象对SQL语句的占位符参数赋值,其参数的下标值不是0而是1,这与数组下标有区别
ps.setInt(1, students.getId());
ps.setString(2, students.getName());
ps.setString(3, students.getSex());
ps.setInt(4, students.getAge());
//使用executeUpdate()方法执行更新操作,并返回int类型整数
int row=ps.executeUpdate();
if (row > 0){
out.print("成功添加了 "+row+" 条数据!");
}
//在执行数据操作之后,应该立即调用Result对象、PreparedStatement对象、Connection对象的close()方法,从而及时释放所占用的数据库资源
ps.close();
conn.close(); }catch(Exception e){
out.print("学生信息添加失败!");
e.printStackTrace();
}
%>
<br>
<a href="index.jsp">返回</a>
</body>
</html>

  效果:

 

数据库中:

2.查询数据

  执行查询数据操作后需要通过一个对象来装载查询结果集,这个对象就是Request对象。Request对象是JDBC API中封装的结果集对象,从数据表中查询到的数据都放置在这个集合中。其结构如下图所示:

    

  从图中可以看出,在Request集合中,通过移动光标来获取查询到的数据,Request对象中的光标可以进行上下移动,如获取Request集合中的一条数据,只需要把光标定位到当前数据光标即可。在第一条数据之前和最后一条数据之后都有一个位置,默认情况下,Request的光标位置在第一行数据之前,所有在第一次获取数据时就需要移动光标位置。

  实例:在上面的项目中创建名为ShowServlet的对象,用于查询所有图书信息。

package com;

import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* Servlet implementation class ShowServlet
*/
@WebServlet("/ShowServlet")
public class ShowServlet extends HttpServlet {
private static final long serialVersionUID = 1L; /**
* @see HttpServlet#HttpServlet()
*/
public ShowServlet() {
super();
// TODO Auto-generated constructor stub
} /**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
try{
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/student";
String username = "root";
String password = "123456";
Connection conn= DriverManager.getConnection(url, username, password);
String sql="select * from student_info";
Statement stmt=conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
//使用PreparedStatement对象对SQL语句的占位符参数赋值,其参数的下标值不是0而是1,这与数组下标有区别
List<Student> list = new ArrayList<Student>();
while(rs.next()) {
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setSex(rs.getString("sex"));
student.setAge(rs.getInt("age"));
list.add(student);
}
request.setAttribute("list", list);
rs.close();
stmt.close();
conn.close(); }catch(ClassNotFoundException e) {
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
request.getRequestDispatcher("student_list.jsp").forward(request, response);
response.getWriter().append("Served at: ").append(request.getContextPath());
} /**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
} }

  创建student_list.jsp页面显示所有学生信息

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.Student" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<table align="center" width="450" border="1px">
<tr>
<td align="center" colspan="4">
<h2>学生信息</h2><hr>
</td>
</tr>
<tr align="center">
<td><b>ID</b></td>
<td><b>姓名</b></td>
<td><b>性别</b></td>
<td><b>年龄</b></td>
</tr>
<%
List<Student>list=(List<Student>)request.getAttribute("list");
if(list == null || list.size() < 1){
out.print("没有数据!");
}else{ for(Student student:list){
%>
<tr>
<td><%=student.getId()%></td>
<td><%=student.getName()%></td>
<td><%=student.getSex()%></td>
<td><%=student.getAge()%></td>
</tr>
<%
}
}
%>
</table>
<br>
<a href="index.jsp">返回</a> </body>
</html>

  同时在index.html中添加

<a href="ShowServlet">查看所有学生信息</a>

   效果:

3.修改数据

  update 表名 set 列名=?where id=?

String sql = "update student_info set name=? where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, s_name);
ps.setInt(2, s_id);
ps.executeUpdate();

4.删除数据

  delete form student_info where id = 1

String sql = "delete student_info where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.executeUpdate();

5.批处理

//Student类中
public Connection getConnection() {
Connection conn=null;
try{
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/student?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";
String username = "root";
String password = "123456";
conn= DriverManager.getConnection(url, username, password);
}catch(ClassNotFoundException e) {
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
return conn;
}
public int saveBatch() {
int row=0;
Connection conn = getConnection();
try{
String sql="insert into student_info(id,name,sex,age) values(?,?,?,?)";
PreparedStatement ps=conn.prepareStatement(sql);
Random random=new Random();
for(int i=0; i< 10; i++) {
ps.setInt(1, i+1);
ps.setString(2, "学生"+i);
ps.setString(3, i%2==0?"male":"female");
ps.setInt(4, random.nextInt(5)+10);
ps.addBatch();//添加批处理命令
}
int[] rows=ps.executeBatch();//执行批处理操作
row = rows.length;
//在执行数据操作之后,应该立即调用Result对象、PreparedStatement对象、Connection对象的close()方法,从而及时释放所占用的数据库资源
ps.close();
conn.close();
}catch(Exception e){
e.printStackTrace();
}
return row;
}

  index.jsp

<jsp:useBean id="batch" class="com.Student"></jsp:useBean>
<%
int row=batch.saveBatch();
out.print("批量插入了 " +row+" 条数据!" );
%>

  效果:

6.调用存储过程

  在JDBC API中提供了调用存储过程的方法,通过CallableStatement对象进行操作。CallableStatement对象位于java.sql包中,它继承了Statement对象,主要用来执行数据库中定义的存储过程,其调用方法如下:

{call <procedure-name>[(<arg1>,<arg2>,......)]}
//arg为存储过程的参数,可对其进行赋值操作。

  存储过程是一个SQL语句和可选控制流语句的预编译集合。编译完成后存放在数据库中,这样就省去了执行SQL语句进行编译所花费的时间。在执行存储过程时只需要将参数传递到数据库中,而不需要将整条SQL语句都提交给数据库,从而减少了网络传输的流量,从另一方面提高了程序的运行速度。

  实例:创建查询所有学生信息的存储过程,通过JDBC API对其调用获取所有图书信息,并将其输出到JSP页面。

 (1)先在Navicat视窗下在数据库student中新建查询创建名为findAllStudent的存储过程。

CREATE PROCEDURE findAllStudent()
BEGIN
SELECT * FROM student_info;
END

 (2)在Student类中加入findAll()函数来执行存储过程

public List<Student> findAll(){
List<Student> list= new ArrayList<Student>();
Connection conn = getConnection();
try {
CallableStatement cs = conn.prepareCall("{call findAllStudent()}");
ResultSet rs = cs.executeQuery();
while(rs.next()) {
Student student = new Student();
student.setId(rs.getInt("id"));
student.setName(rs.getString("name"));
student.setSex(rs.getString("sex"));
student.setAge(rs.getInt("age"));
list.add(student);
}
}catch(Exception e){
e.printStackTrace();
}
return list;
}

 (3)在原student_list.jsp中修改,用JavaBean来实例化Student

<jsp:useBean id = "findStudent" class="com.Student"></jsp:useBean>

...
<table>
...
List<Student>list=findStudent.findAll();

四.JDBC在Java Web中的应用

1.分页查询

  在数据库量非常大的情况下,不适合将所有数据都显示到一个页面。通过JDBC实现分页查询的方式有很多种,而且不同的数据库机制也提供了不同的分页方式,两种非常经典的分页方法。

通过ResultSet的光标实现分页

  光标通过上下移动定位查询结果集的行,从而获取数据。可以设置Result对象中记录的起始位置,来实现分页显示。

  优点是在各种数据库上通用,缺点2是占用大量资源,不适合大数据。所以实际开发都是采用数据库提供的分页查询实现的。

  SELECT * FROM *** WHERE *** ORDER BY *** LIMIT  arg1, arg2

  arg1:指定查询记录的起始位置

  arg2:指定查询数据返回的记录数

通过数据库机制进行分页

  如SQL Server中提供的top关键字,MySQL数据库提供的limit关键字,它们都可以设置数据返回的记录数。

  实例:将上面的学生信息分页显示

  在Student类中加入

public static final int PAGE_SIZE = 5;
//每页记录数,静态变量可直接引用,因为该值不会经常修改,所以定义为final类型。
//在java中,通常将final类型的变量大写
/**
为了简单,所以我每次都把这些方法放到了Student类中,实际上应该分开
* 分页查询所有信息
* @param page 页数
* @return List<Student>
*/
public List<Student> find(int page){
List<Student> list = new ArrayList<Student>();
Connection conn = getConnection();
String sql = "SELECT * FROM student_info LIMIT ?,?";
try{
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1, (page-1)*Student.PAGE_SIZE);
ps.setInt(2, Student.PAGE_SIZE);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
Student s = new Student();
s.setId(rs.getInt("id"));
s.setName(rs.getString("name"));
s.setSex(rs.getString("sex"));
s.setAge(rs.getInt("age"));
list.add(s);
}
rs.close();
ps.close();
conn.close();
}catch(Exception e){
e.printStackTrace();
}
return list;
}
/**
*查询总记录数
*@return 总记录数
*/
public int findCount() {
int count = 0;
Connection conn = getConnection();
String sql = "select count(*) from student_info";
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
if(rs.next())
count = rs.getInt(1);
rs.close();
conn.close();
}catch(SQLException e) {
e.printStackTrace();
}
return count;
}

  在ShowServlet类中的doGet()做获取分页查询结果和构造分页条对象

        int currPage = 1;    //当前页码
if(request.getParameter("page") != null) {
currPage = Integer.parseInt(request.getParameter("page"));
}
Student s = new Student();
List<Student>list = s.find(currPage);
request.setAttribute("list", list);
int totalPages; //总页数
int count = s.findCount(); //查询总页数
if(count % Student.PAGE_SIZE == 0)
totalPages = count / Student.PAGE_SIZE;
else
totalPages = count / Student.PAGE_SIZE+1;
StringBuffer sb = new StringBuffer();
     /*如果一个字符串经常发生变化,应该使用StringBuffer对字符进行操作。因为在JVM中,
每次创建一个新的字符串,都需要分配一个字符串空间,而StringBuffer则是字符串缓冲区,
    性能更高。*/
for (int i = 1; i <= totalPages; i++) {  //构建分页条
if(i == currPage)
sb.append("[" + i + "]");
else
sb.append("<a href='ShowServlet?page="+i+"'>"+i+"</a>");
sb.append(" ");
}
request.setAttribute("bar", sb.toString());
request.getRequestDispatcher("student_list.jsp").forward(request, response);

  在student_list.jsp中修改

  

List<Student>list=(List<Student>)request.getAttribute("list");

......
<tr>
<td align="center" colspan="4">
<%=request.getAttribute("bar") %>
</td>
</tr>

  效果:

7.Java Web的数据库操作的更多相关文章

  1. Java Web的数据库操作(一)

    一.JDBC技术 1.JDBC简介 JDBC是Java程序与数据库系统通信的标准API,它定义在JDK的API中,通过JDBC技术,Java程序可以非常方便地与各种数据库交互,JDBC在Java程序与 ...

  2. java web工程 数据库操作报驱动类找不到的错误

    这几天在进行数据库的操作,写好数据库操作类后,用测试类测试成功通过,但是部署到tomcat后,从页面访问就会报异常. 最后终于发现是tomcat使用了连接池的数据连接方式. 解决方法是把jdbc ja ...

  3. Java Web----Java Web的数据库操作(一)

    Java Web的数据库操作 一.JDBC技术 1.JDBC简介 JDBC是Java程序与数据库系统通信的标准API,它定义在JDK的API中,通过JDBC技术,Java程序可以非常方便地与各种数据库 ...

  4. Java Web----Java Web的数据库操作(二)

    Java Web的数据库操作 三.JDBC操作数据库 上一篇介绍了JDBC API,之后就可以通过API来操作数据库,实现对数据库的CRUD操作了. http://blog.csdn.net/zhai ...

  5. Java Web----Java Web的数据库操作(三)

    Java Web的数据库操作 前面介绍了JDBC技术和JDBC API及API的使用示例,下面详细介绍JDBC在Web中的应用. Java Web----Java Web的数据库操作(一) Java ...

  6. 2017.11.5 Java Web ----案例:数据库访问JavaBean的设计

    (12)案例----数据库访问JavaBean的设计 例题:数据库操作在一个Web应用程序中的后台处理中占有大比重,设计一组JavaBean封装数据库的基本操作供上层模块调用,提高程序的可移植性. [ ...

  7. java工具类--数据库操作封装类

    java对数据库操作简单处理,如下代码即可,封装了 增删改查及获取连接.关闭连接. 代码如下: package com.test; import java.sql.Connection; import ...

  8. HTML5 Web SQL 数据库操作

    Web SQL 数据库 API 并不是 HTML5 规范的一部分,但是它是一个独立的规范,引入了一组使用 SQL 操作客户端数据库的 APIs. 以下是规范中定义的三个核心方法: openDataba ...

  9. 二十三、java连接oracle数据库操作:jdbc

    1.jdbc 1) 含义:JDBC是java语言连接数据库,Java Date Base Connectivity2) jdbc的本质:在编程时java程序会去连接不同的数据库,而每个数据库的底层的实 ...

随机推荐

  1. flask项目配置

    config.py: class Config(object): """项目的配置""" DEBUG = True SECRET_KEY = ...

  2. Dom编程-左侧菜单栏设计模型实现

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. C++入门基础知识(一)

    一:关键字 在C语言中,我们已经学习过了很多的关键字,例如:static,struct等,下面展现一下C++中的一些关键字. 二:命名空间 在C/C++中,变量.函数和类都是大量存在的,这些变量.函数 ...

  4. 树莓派安装使用RXTX

    在RaspberryPi树莓派上使用RXTX(RXTX的源码安装)Linux 编译RXTX(JAVA串口开发)源码 如果为windows系统,则使用rxtx比较简单,到http://fizzed.co ...

  5. C#面向对象11 里氏转换

    里氏转换 1.子类可以赋值给父类. using System; using System.Collections.Generic; using System.Linq; using System.Te ...

  6. js判断一个 object 对象是否为空

    方法一:使用for...in for...in... 遍历属性,为真则为“非空数组”:否则为“空数组” for (var i in obj) { return true  // 如果不为空,则会执行到 ...

  7. [转载]深入理解maven构建生命周期和各种plugin插件

    我就不复制博主文章了,到原文地址看吧.写这个只是为了自己搜索起来方便些: https://blog.csdn.net/zhaojianting/article/details/80321488 htt ...

  8. JavaWeb【五、内置对象】

    简介 Web容器创建的一组对象,不用new即可使用. 共有9种,out.request.response.session.application,五种比较常用,page.pageContent.exc ...

  9. Python—selenium模块(浏览器自动化工具)

    selenium可以用来完成浏览器自动化相关的操作,写一些代码制定一些基于浏览器自动化的相关操作(行为动作),当代码执行后,浏览器就会自动触发相关的事件 安装方法: pip install selen ...

  10. JS批量绑定事件

    ,,,,] for(var j in a){ $("#" + j).click(function () { // 前提是先动态生成id是j的标签 var id_cm = $(thi ...