Blog

mybatis动态sql-(6)-批量插入foreach与sql片段抽取

mysql批量插入与oracle批量插入不同

一、搭建数据库

tbl_employee表【d_id 是外键 对应 tbl_dept表】

id	last_name    gender	  email       d_id
1	   mike	       0      [email protected]      1
2          book        0      [email protected]    2
3          tom         1      [email protected]    2
4          jerry       1       [email protected]       1

tbl_dept表:

id    dept_name
1      开发部
2      测试部

二、编辑javabean

package com.mybatis.bean;

public class Employee {
	private Integer id;
	private String lastName;
	private String email;
	private String gender;
	private Department department;

	
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
	}
	
   /*****  关键是 这个地方啊 出了 问题 ****/
	public Employee() {
		super();
	}
	/*****/
	public Employee(Integer id,String lastName, String  email, String gender){
		this.id =id;
		this.lastName =lastName;
		this.email =email;
		this.gender =gender;
		
	}
	
	public Employee(Integer id,String lastName, String  email, String gender,Department dep){
		this.id =id;
		this.lastName =lastName;
		this.email =email;
		this.gender =gender;
		this.department =dep;
	}
	
//  历史教训 ,一开始 没有添加 无参构造函数,而添加了下面这个函数	
//	public Employee(Integer id,String lastName, String  email, String gender,int temp){
//		this.id =id;
//		this.lastName =lastName;
//		this.email =email;
//		this.gender =gender;
//		
//		System.out.println(" id:"+id+" lastName:"+lastName+" email:"+email+" gender:"+gender+" temp:"+temp);
//	}

}
package com.mybatis.bean;

import java.util.List;

public class Department {

	private Integer id;
	private String departmentName;
	private List<Employee> employees;

	public Department() {
		
	}
	
    public Department(int id){
    	this.id = id;
		
	}

	public List<Employee> getEmployees() {
		return employees;
	}

	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getDepartmentName() {
		return departmentName;
	}

	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}

	@Override
	public String toString() {
		return "Department [id=" + id + ", departmentName=" + departmentName + "]";
	}

}

 

三、编辑junit测试

@Test
public void testBatchSave() throws IOException{
	SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
	SqlSession openSession = sqlSessionFactory.openSession();
	try{
		EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
		List<Employee> emps = new ArrayList<>();
		emps.add(new Employee(null, "smith0x1", "[email protected]", "1" , new Department(1) ));
		emps.add(new Employee(null, "allen0x1", "[email protected]", "0" , new Department(1) ));
		mapper.addEmps(emps);
		openSession.commit();
	}finally{
		openSession.close();
	}
}

四、编辑SQl映射文件

1、mysql 版

 <!--MySQL下批量保存:可以foreach遍历   mysql支持values(),(),()语法-->
<!-- 批量保存 -->
 <!--public void addEmps(@Param("emps")List<Employee> emps);  -->
 <!--MySQL下批量保存:可以foreach遍历   mysql支持values(),(),()语法-->
<insert id="addEmps">
	 insert into tbl_employee(last_name,email,gender,d_id) 
	values
	<foreach collection="emps" item="emp" separator=",">
		(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
	</foreach>
 </insert><!--   -->
	 
 <!-- 这种方式需要数据库连接属性allowMultiQueries=true;
	 这种分号分隔多个sql可以用于其他的批量操作(删除,修改) -->
 <!-- <insert id="addEmps">
	 <foreach collection="emps" item="emp" separator=";">
	 	insert into tbl_employee(last_name,email,gender,d_id)
	 	values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
	 </foreach>
 </insert> -->

mysql补充:在mysql配置时,我们可能需要配置 allowMultiQueries=true
jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true

若一个sql中通过分号分割(或包含)了多个独立sql的话,如:
select 'hello';select 'world'
就会报如下错:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select 'world'' at line 1
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

当若显式设置allowMultiQueries为true的话,就可以正常执行不会报错.如下所示:
String url = "jdbc:mysql://localhost:3306?allowMultiQueries=true";

官方文档解释:
allowMultiQueries
Allow the use of ';' to delimit multiple queries during one statement (true/false), defaults to 'false', and does not affect the addBatch() and executeBatch() methods, which instead rely on rewriteBatchStatements.
Default: false
Since version: 3.1.1

2、oracle版

 <!-- Oracle数据库批量保存: 
	 Oracle不支持values(),(),()
	 Oracle支持的批量方式
	 1、多个insert放在begin - end里面
	 	begin
		     insert into employees(employee_id,last_name,email) 
		     values(employees_seq.nextval,'test_001','[email protected]');
		     insert into employees(employee_id,last_name,email) 
		     values(employees_seq.nextval,'test_002','[email protected]');
		end;
	2、利用中间表:
		insert into employees(employee_id,last_name,email)
		   select employees_seq.nextval,lastName,email from(
		          select 'test_a_01' lastName,'test_a_e01' email from dual
		          union
		          select 'test_a_02' lastName,'test_a_e02' email from dual
		          union
		          select 'test_a_03' lastName,'test_a_e03' email from dual
		   )	
	 -->

实际写法:

<insert id="addEmps" databaseId="oracle">
	 <!-- oracle第一种批量方式 -->
	 <!-- <foreach collection="emps" item="emp" open="begin" close="end;">
	 	insert into employees(employee_id,last_name,email) 
		      values(employees_seq.nextval,#{emp.lastName},#{emp.email});
	 </foreach> -->
	 	
	 <!-- oracle第二种批量方式  -->
	 insert into employees(
	 	<!-- 引用外部定义的sql -->
	 	<include refid="insertColumn">
	 		<property name="testColomn" value="abc"/>
	 	</include>
	 )
	 		<foreach collection="emps" item="emp" separator="union"
	 			open="select employees_seq.nextval,lastName,email from("
	 			close=")">
	 			select #{emp.lastName} lastName,#{emp.email} email from dual
	 		</foreach>
 </insert>

特别提醒一下:下面的引用其实就是 待插入的 各个字段啦。

<!-- 引用外部定义的sql -->
	 <include refid="insertColumn">
	 	<property name="testColomn" value="abc"/>
	 </include>

用法说明:不是只能用在批量插入中,也可以用在其他数据操作中,因为只是对SQL片段的抽取。

 <!-- 
	  抽取可重用的sql片段。方便后面引用 
	  1、sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
	  2、include来引用已经抽取的sql:
	  3、include还可以自定义一些property,sql标签内部就能使用自定义的属性
	  		include-property:取值的正确方式${prop},
	  		#{不能使用这种方式}
          4、employee_id,last_name,email,${prop} 这个oracle插入 其实等价于【当然数据库有没有相应字段是另一回事,在这里只是用来演示】 employee_id,last_name,email,abc
          5、_databaseId 是 mybatis 内置参数,和在 全局配置文件中,标记的数据库 名是 一样的
-->
  <sql id="insertColumn">
	  	<if test="_databaseId=='oracle'">
	  		employee_id,last_name,email,${prop}
	  	</if>
	  	<if test="_databaseId=='mysql'">
	  		last_name,email,gender,d_id
	  	</if>
 </sql>

 

mybatis动态sql-(5)-遍历查询foreach

一、编写接口方法:

package com.mybatis.mapper;

import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.mybatis.bean.Employee;

public interface EmployeeMapperDynamicSQL {
	
	//查询员工id'在给定集合中的
	public List<Employee> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);

}

 二、编写sql映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.EmployeeMapperDynamicSQL">

<!--public List<Employee> getEmpsByConditionForeach(List<Integer> ids);  -->
<select id="getEmpsByConditionForeach" resultType="com.mybatis.bean.Employee">
	 select * from tbl_employee
	 <!--
	 测试用例:
	 select * from tbl_employee where id in (1,2,3)
	 	
	 	collection:指定要遍历的集合:
	 		list类型的参数会特殊处理封装在map中,map的key就叫list
	 	item:将当前遍历出的元素赋值给指定的变量
	 	separator:每个元素之间的分隔符
	 	open:遍历出所有结果拼接一个开始的字符
	 	close:遍历出所有结果拼接一个结束的字符
	 	index:索引。遍历list的时候是index就是索引,item就是当前值
	 		   遍历map的时候index表示的就是map的key,item就是map的值
	 		
	 	#{变量名}就能取出变量的值也就是当前遍历出的元素
	  -->
	 <foreach collection="ids" item="item_id" separator=","
	 	open="where id in(" close=")">
	 	#{item_id}
	 </foreach>
</select>

</mapper>

 三、编写Junit测试

List<Employee> list = mapper.getEmpsByConditionForeach(Arrays.asList(1,2));
     for (Employee emp : list) {
	 System.out.println(emp);
}

 

mybatis动态sql-(4)-多次条件判断set和trim

当更新数据时,可以用 set 标签 来,来取消 更新语句中 多余的,
last_name=#{lastName}, 
比如上面这句话,如果是最后一个判断子句,那末尾的[,]是要去掉的,所以就需要用set标签了。trim标签之前提到过,功能很多,可以去头和去尾,也可以添加整句头和添加整句尾。

<!--public void updateEmp(Employee employee);  -->
<update id="updateEmp">
	 <!-- Set标签的使用 -->
	 update tbl_employee 
	<set>
		<if test="lastName!=null">
			last_name=#{lastName},
		</if>
		<if test="email!=null">
			email=#{email},
		</if>
		<if test="gender!=null">
			gender=#{gender}
		</if>
	</set>
	where id=#{id} 
<!-- 		
	Trim:更新拼串
	update tbl_employee 
	<trim prefix="set" suffixOverrides=",">
		<if test="lastName!=null">
			last_name=#{lastName},
		</if>
		<if test="email!=null">
			email=#{email},
		</if>
		<if test="gender!=null">
			gender=#{gender}
		</if>
	</trim>
	where id=#{id}  -->
 </update>

 

mybatis动态sql-(3)-单次条件判断choose

单次判断,就是只进行一次判断。

一、编辑接口文件

import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.mybatis.bean.Employee;

public interface EmployeeMapperDynamicSQL {

       public List<Employee> getEmpsByConditionChoose(Employee employee);

}

二、编辑SQL映射文件

 <!-- public List<Employee> getEmpsByConditionChoose(Employee employee); -->
 <select id="getEmpsByConditionChoose" resultType="com.mybatis.bean.Employee">
	 select * from tbl_employee 
	 <where>
	 	<!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
	 	<choose>
	 		<when test="id!=null">
	 			id=#{id}
	 		</when>
	 		<when test="lastName!=null">
	 			last_name like #{lastName}
	 		</when>
	 		<when test="email!=null">
	 			email = #{email}
	 		</when>
	 		<otherwise>
	 			gender = 0
	 		</otherwise>
	 	</choose>
	 </where>
 </select>

三、Junit单元测试

EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
Employee employee = new Employee(3,"%m%","[email protected]","2");

List<Employee> list = mapper.getEmpsByConditionChoose(employee);
	for(Employee emp :list){
	System.out.println(emp);
	System.out.println(emp.getDepartment());
}

 

mybatis动态sql-(2)-多次条件判断where和trim

在前面一中:

sql映射文件:只用到了if,如果 条件一 id 是null;

那么sql 语句 就成了select * from tbl_employee  where  and  id=#{id}   会报错

<select id="getEmpsByConditionIf" resultType="com.mybatis.bean.Employee">
	 	select * from tbl_employee where
	 	
		 	<!-- test:判断表达式(OGNL)
		 	OGNL参照PPT或者官方文档。
		 	  	 c:if  test
		 	从参数中取值进行判断
		 	
		 	遇见特殊符号应该去写转义字符:
		 	&&:
		 	-->
		 	<if test="id!=null">
		 		id=#{id}
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		and email=#{email}
		 	</if> 
		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	and gender=#{gender}
		 	</if>
	 	
	 </select>


</mapper>

查询的时候如果某些条件没带可能sql拼装会有问题。

一、SQL条件语句问题简单解决方法

1、将SQL语句写成select * from tbl_employee  where  1=1
后面的条件语句都写成: and xxx 之类的。
2、mybatis使用where标签来将所有的查询条件包括在内。mybatis就会将where标签中拼装的sql,多出来的and或者or去掉where只会去掉第一个多出来的and或者or。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.EmployeeMapperDynamicSQL">
<!-- 
上面的 namespace:名称空间;指定为接口的全类名
下面的 id:唯一标识被规定为接口方法名 【public Employee getEmpById(Integer id);】
下面的 resultType:返回值类型
下面的 #{id}:从传递过来的参数中取出id值
 -->
	
<!-- 
• if:判断
• choose (when, otherwise):分支选择;带了break的swtich-case
	如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个
• trim 字符串截取(where(封装查询条件), set(封装修改条件))
• foreach 遍历集合
	 -->
	 <!-- 查询员工,要求,携带了哪个字段查询条件就带上这个字段的值 -->
	 <!-- public List<Employee> getEmpsByConditionIf(Employee employee); -->
<select id="getEmpsByConditionIf" resultType="com.mybatis.bean.Employee">
	 	select * from tbl_employee
	 	
	 	<!-- where -->
	 	<where>
		 	<!-- test:判断表达式(OGNL)
		 	OGNL参照PPT或者官方文档。
		 	  	 c:if  test
		 	从参数中取值进行判断
		 	
		 	遇见特殊符号应该去写转义字符:
		 	&&:
		 	-->
		 	<if test="id!=null">
		 		id=#{id}
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		and email=#{email}
		 	</if> 
		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	and gender=#{gender}
		 	</if>
	 	</where>
	 </select>


</mapper>

二、SQL条件语句问题高级解决方法

采用 trim 字符串截取方法:

<!--public List<Employee> getEmpsByConditionTrim(Employee employee);  -->
 <select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
	 select * from tbl_employee
	 <!-- 后面多出的and或者or where标签不能解决 
	 prefix="":前缀:trim标签体中是整个字符串拼串 后的结果。
	 		prefix给拼串后的整个字符串加一个前缀 
	 prefixOverrides="":
	 		前缀覆盖: 去掉整个字符串前面多余的字符
	 suffix="":后缀
	 		suffix给拼串后的整个字符串加一个后缀 
	 suffixOverrides=""
	 		后缀覆盖:去掉整个字符串后面多余的字符
	 			
	 -->
	 <!-- 自定义字符串的截取规则 -->
	 <trim prefix="where" suffixOverrides="and">
	 	<if test="id!=null">
		 	id=#{id} and
		 </if>
		 <if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 	last_name like #{lastName} and
		 </if>
		 <if test="email!=null and email.trim()!=&quot;&quot;">
		 	email=#{email} and
		 </if> 
		 <!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
		 <if test="gender==0 or gender==1">
		 	 gender=#{gender}
		 </if>
	 </trim>
</select>

 

mybatis动态sql-(1)-多次条件判断If和OGNL

1、搭建数据库

tbl_employee表【d_id 是外键 对应 tbl_dept表】

id	last_name    gender	  email       d_id
1	   mike	       0      [email protected]      1
2          book        0      [email protected]    2
3          tom         1      [email protected]    2
4          jerry       1       [email protected]       1

tbl_dept表:

id    dept_name
1      开发部
2      测试部

2、编辑 javabean

特别要提醒:因为是在测试代码中,需要用到自定义Employee构造函数,所以这里为了能让mybatis正常使用反思,一定要添加Employee的无参构造函数。

Employee.java

package com.mybatis.bean;

public class Employee {
	private int id;
	private String lastName;
	private String email;
	private String gender;
	private Department department;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}
	
	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
	}

       /*****  关键是 这个地方啊 出了 问题 ****/
	public Employee() {
		super();
	}
	/*****/
	public Employee(int id,String lastName, String  email, String gender){
		this.id =id;
		this.lastName =lastName;
		this.email =email;
		this.gender =gender;
	}

}

Department.java

package com.mybatis.bean;

import java.util.List;

public class Department {
	
	private Integer id;
	private String departmentName;
        private List<Employee> employees;
        
        public List<Employee> getEmployees() {
		return employees;
	}
	public void setEmployees(List<Employee> employees) {
		this.employees = employees;
	}

	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getDepartmentName() {
		return departmentName;
	}
	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}
	@Override
	public String toString() {
		return "Department [id=" + id + ", departmentName=" + departmentName
				+ "]";
	}
	
	

}

三、编辑接口文件

EmployeeMapperDynamicSQL.java

package com.mybatis.mapper;

import java.util.List;

import com.mybatis.bean.Employee;

public interface EmployeeMapperDynamicSQL {

	//携带了哪个字段查询条件就带上这个字段的值
	public List<Employee> getEmpsByConditionIf(Employee employee);
	
}

四、SQL映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.EmployeeMapperDynamicSQL">
<!-- 
上面的 namespace:名称空间;指定为接口的全类名
下面的 id:唯一标识被规定为接口方法名 【public Employee getEmpById(Integer id);】
下面的 resultType:返回值类型
下面的 #{id}:从传递过来的参数中取出id值
 -->
	
<!-- 
• if:判断
• choose (when, otherwise):分支选择;带了break的swtich-case
	如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个
• trim 字符串截取(where(封装查询条件), set(封装修改条件))
• foreach 遍历集合
	 -->
	 <!-- 查询员工,要求,携带了哪个字段查询条件就带上这个字段的值 -->
	 <!-- public List<Employee> getEmpsByConditionIf(Employee employee); -->
<select id="getEmpsByConditionIf" resultType="com.mybatis.bean.Employee">
	 	select * from tbl_employee
	 	where
                <!-- where -->
	 	
		 	<!-- test:判断表达式(OGNL)
		 	OGNL参照PPT或者官方文档。
		 	  	 c:if  test
		 	从参数中取值进行判断
		 	
		 	遇见特殊符号应该去写转义字符:
		 	&&:
		 	-->
		 	<if test="id!=null">
		 		id=#{id}
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		and email=#{email}
		 	</if> 
		 	<!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	and gender=#{gender}
		 	</if>
	 	
	 </select>


</mapper>

五、全局配置文件

添加了,驼峰映射 大小写 自动转换 配置 setting。
因为从数据库中,选择出来了的就 只有5个字段,这5个字段,自动映射到Employee中,然后 d_id字段无法和bean中的department 属性映射,所以被废弃。department就为null了。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
	</settings>

	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
				<property name="username" value="root" />
				<property name="password" value="Cool123!" />
			</dataSource>
		</environment>
	</environments>
	<!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 
	如果 数据库全局文件 和 子配置文件 不在同一个目录 ,就需要 /目录/目录/.../EmployeeMapper_old.xml
	-->
	<mappers>
	
	    <!-- 新方法操作mybatis 需要 的配置文件 -->
		<mapper resource="EmployeeMapperDynamicSQL.xml" />
	</mappers>
</configuration>

六、Junit单元测试

department属性,是没有赋值的,这里要注意一下。
sql语句的条件判断是OK的。

package com.mybatis.test;


import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import com.mybatis.bean.Employee;
import com.mybatis.mapper.EmployeeMapperDynamicSQL;


/**
 * 1、接口式编程
 * 	原生:		Dao		====>  DaoImpl
 * 	mybatis:	Mapper	====>  xxMapper.xml
 * 
 * 2、SqlSession代表和数据库的一次会话;用完必须关闭;
 * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。(就是不要放在共享成员变量里面,A线程用完释放,B线程再用就为空了)
 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。
 * 		(将接口和xml进行绑定)
 * 		EmployeeMapper empMapper =	sqlSession.getMapper(EmployeeMapper.class);
 * 5、两个重要的配置文件:
 * 		mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
 * 		sql映射文件:保存了每一个sql语句的映射信息:
 * 					将sql抽取出来。	
 *
 */

public class MybatisTest {


	public SqlSessionFactory getSqlSessionFactory() throws IOException {
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		return new SqlSessionFactoryBuilder().build(inputStream);
	}
	
	@Test
	public void test_new() throws IOException {
		// 1、获取sqlSessionFactory对象
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		// 2、获取sqlSession对象
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			// 3、获取接口的实现类对象
			//会为接口自动的创建一个代理对象,代理对象去执行增删改查方法
			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
			Employee employee = new Employee(3,"%m%","[email protected]","1");
			List<Employee> list = mapper.getEmpsByConditionIf(employee);
			for(Employee emp :list){
				System.out.println(emp);
				System.out.println(emp.getDepartment());

			}
		} finally {
			openSession.close();
		}

	}

}

 

mybatis基础-关键注意点bean的构造函数问题

当我用Junit单元测试,来学习mybatis时:

mybatis的bean文件中,采用的是默认构造函数。

当bean需要自定义构造函数时,一定要记得顺便 添加一个 无参构函数。因为mybatis用到了反射。无参构造函数是必须的。

如果自定义构造函数后,忘记添加了默认无参构造函数,那么就会报错。说缺少(,,,)形式的构造函数,但是不会说缺少无参构造函数。这个要注意啦。

 

测试踩坑-Junit单元测试时进程sleep连接数据库超时

最近,在用junit单元测试 mybatis。

发现偶尔会出现,代码全部是正确的,但是junit会在控制台 一直占用着,没有任何信息输出。也就是控制台 一直都是 显示 红点,按下红点,就能把控制台进程关闭了。

于是debug了一下,发现一直在连接数据库,然后超时的缘故。

估计了一下,应该是数据库没有任何返回信息,用mysql的客户端能连接,说明是eclipse的 数据库连接出 了问题,应该是eclipse 数据库连接 进程被占用了吧。

后来,我用 mac 系统的强制 关闭 eclipse,然后过一段时间 ,打开,发现 junit单元测试,终于打印出信息了,终于好用了啦。

fuck 终于找到原因了,是代理问题,我开了全局代理。导致eclipse 一直连接不上 mysql,后来关了代理  就行了。

java入门概述

Java 语言

跟任何编程语言一样,Java 语言拥有自己的结构、语法规则和编程范例。Java 语言的编程范例基于面向对象编程 (OOP) 的概念,该语言的特性支持这一概念。

Java 语言是 C 语言的一种衍生语言,所以它的语法规则与 C 语言的语法规则非常相似。例如,方法使代码模块化并使用花括号({ 和 })分隔,变量需要在使用之前声明。

在结构上,Java 语言以 作为开头。包是 Java 语言的命名空间机制。包中包含类,而类中包含方法、变量、常量等。您将在本学习路径中了解 Java 语言的各个部分。

Java 编译器

在 Java 平台编写程序时,您会在 .java 文件中编写源代码,然后编译它们。编译器针对语言的语法规则来检查代码,然后将字节码 写出到 .class 文件中。字节码是一组需要在 Java 虚拟机 (JVM) 上运行的指令。添加了这一抽象级别后,Java 编译器不同于其他语言编译器,其他编译器会写出适合运行程序的 CPU 芯片集的汇编语言指令。

JVM

在运行时,JVM 读取并解释 .class 文件,在编写的 JVM 的目标原生硬件平台上执行程序的指令。JVM 解释字节码就像 CPU 解释汇编语言指令一样。不同之处在于,JVM 是一个专为特定平台编写的软件。JVM 是 Java 语言的 “编写一次、随处运行” 原则的核心。您的代码可在任何拥有合适的 JVM 实现的芯片集上运行。JVM 可用于 Linux 和 Windows 等主要平台,在针对移动电话和爱好者芯片的 JVM 中也已实现了 Java 语言的子集。

垃圾收集器

Java 平台不会强制您时刻关注内存分配(或使用第三方库来完成此工作),它提供了开箱即用的内存管理功能。当您的 Java 应用程序在运行时创建一个对象实例时,JVM 会自动从 中为该对象分配内存空间— 堆是一个专门留给您的程序使用的内存池。Java 垃圾收集器 在后台运行,跟踪记录应用程序不再需要哪些对象并从它们回收内存。这种内存处理方法称为隐式内存管理,因为它不需要您编写任何内存处理代码。垃圾收集是 Java 平台性能的基本特征之一。

Java 开发工具包

下载 Java 开发工具包 (JDK),您会获得 — 包括编译器和其他工具 — 包含预构建的实用程序的完整类库,以帮助您完成最常见的应用程序开发任务。了解 JDK 包和库的范围的最佳方式是查阅 官方在线 Java API 文档— 也称为 Javadoc。可观看这个快速演示,了解如何浏览 Javadoc。

Java 运行时环境

Java 运行时环境(JRE;也称为 Java 运行时)包含 JVM、代码库和运行以 Java 语言编写的程序所必要的组件。JRE 可用于多种平台。您可依据 JRE 许可条款,在您的应用程序中自由地重新分发 JRE,为应用程序的用户提供一个运行您的软件的平台。JRE 包含在 JDK 中。


建议《Effective Java》、《Java编程思想》以及《重构:改善既有代码质量》是Java程序员必看书籍

1、java 值传递与 引用传递。【 深拷贝 与 浅拷贝 问题】

2、String 类问题

3、java 访问权限问题。【类的权限  和 类方法类变量的权限】

来自:https://www.ibm.com/developerworks/cn/java/j-perry-java-platform-overview/index.html

mysql脚本-mysql自动检测宕机重启并邮件通知

1、mysql检测运行状态:

### -ppassword  其中-p 代表密码参数  后面紧跟的是 password 代表数据库密码
mysqladmin -u root -ppassword ping

2、检测脚本:

#!/bin/bash

#  `  斜引号,代表 将命令行结果 返回值 传给 result 变量
 result=`mysqladmin -u root -pKing123456! ping`

# result=`/usr/bin/mysqladmin ping`

expected='mysqld is alive'

if [[ "$result" = "$expected" ]]

then

echo "mysqld is alive"

else

echo "It's dead - restart mysql"

# email subject

SUBJECT="[MYSQL ERROR] - Attempting to restart service"

# Email To ?

EMAIL="[email protected]"

# Email text/message

EMAILMESSAGE="/tmp/emailmessage.txt"

echo "$result was received"> $EMAILMESSAGE

echo "when we were expected $expected" >>$EMAILMESSAGE

# send an email using /bin/mail

mail -s "$SUBJECT" "$EMAIL" < $EMAILMESSAGE

sudo vncserver -kill :1

sudo systemctl restart mysqld

fi

3、将检测脚本放入定时器中:

### 编辑 用户 定时器文件
crontab -e
### 定义 每隔 半小时 检测 mysql 运行状态
*/30 * * * *  sh  /root/alarm/mysql-watch.sh

4、脚本文件中 发邮件功能解析

mail -s "$SUBJECT" "$EMAIL" < $EMAILMESSAGE

1、安装 sendmail 和 mailx
2、配置smtp文件
3、运行 脚本

参看sendmail配置smtp发邮件