www.350.vip:一回向表中插入多条数据的不二等秘书籍分享,使用mapper动态代理

转自:)

单表的CURD操作(使用mapper动态代理)

MyBatis框架抛开dao的实现类,直接定位到映射文件mapper的相应sql语句,对DB进行操作。这种dao的实现方式成为mapper的动态代理方式。

mapper动态代理方式无需程序员实现dao接口。接口是由MyBatis结合映射文件自动生成的动态代理实现的。

1.映射文件的namespace属性值

一般情况下,一个dao接口的实现类方法使用的是同一个sql映射文件中的sql映射id。所以,MyBatis框架要求,将映射文件中<mapper/>标签的namespace属性设为dao接口的全类名,则系统会根据方法所属dao接口,自动到相应namespace的映射文件中查找相关的sql映射。

简单来说,通过接口名即可定位到映射文件mapper。

2.修改日志输出控制文件

mapper的namespace修改了,则需要将日志输出控制文件中的logger的输出对象进行修改

##define a logger
#log4j.logger.namespace_value=trace,console
log4j.logger.com.hcx.dao.IStudentDao=trace,console

3.dao接口方法名

MyBatis框架要求,接口中的方法名,与映射文件中相应的sql标签的id值相同。系统会自动根据方法名到相应的映射文件中查找同名的sql映射id。

简单来说,通过方法名就可定位到映射文件mapper中相应的sql语句。

接口:

public interface IStudentDao {

    int insertStudent(Student student); 
    void deleteStudentById(int id);
    void updateStudent(Student student);

    List<Student> selectAllStudents();
    Map<String, Object> selectAllStudentsMap();

    Student selectStudentById(int id);
    List<Student> selectStudentsByName(String name);

}

映射:

<select id="selectStudnetById" parameterType="int" resultType="com.hcx.beans.Student">
    select id,name,age,score,birthday from student where id=#{id}
</select>

4.dao对象的获取

使用时,只需要调用Sqlsession的getMapper()方法,即可获取指定接口的实现类对象。该方法的参数为指定dao接口类的class值。

session = factory.openSession();
dao = session.getMapper(IStudentDao.class);

5.删除dao实现类

由于通过调用dao接口的方法,不仅可以从sql映射文件中找到所要执行sql语句,还可通过方法参数及返回值,将sql语句的动态参数传入,将查询结果返回。所以,dao的实现工作,完全可以由MyBatis系统自动根据映射文件完成。所以,dao的实现类就不再需要了。

dao实现对象是由jdk的proxy动态代理自动生成的。

6.测试类

1.在before注解方法中获取到Sqlsession对象后,通过Sqlsession的getMapper方法创建dao接口实现类的动态代理对象。在after注解方法中关闭Sqlsession对象。

public class MyTest {

    private IStudentDao dao;
    private SqlSession session;

    @Before
    public void setUp(){
        session = MyBatisUtils.getSqlSession();
        dao = session.getMapper(IStudentDao.class);
    }

    @After
    public void tearDown(){
        if(session!=null){
            session.close();
        }
    }
}

2.添加Sqlsession的提交方法

在增删改测试方法的最后,添加Sqlsession的commit方法,完成提交。

@Test
public void test01(){
    Student student = new Student("张三",23,99.8);
    dao.insertStudent(student);
    session.commit();
}

@Test
public void test02(){
    Student student = new Student("张三",23,99.8);
    dao.insertStudentCatchId(student);
    System.out.println("student="+student);
    session.commit();
}

@Test
public void test03(){
    dao.deleteStudentById(3);   
    session.commit();
}

3.删除selectStudentMap()方法测试

MyBatis框架对于dao查询的自动实现,底层只会调用selectOne与selectList()方法。而框架选择方法的标准是测试类中用户接收返回值得对象类型。若接收类型为list,则自动选择selectList()方法;否则,自动选择selectOne()方法。

接收类型为map,所以框架选择了selectOne()方法,会报错。

7.多查询条件无法整体接收问题的解决

在实际工作中,表单中所给出的查询条件有时是无法将其封装为一个对象的,也就是说,查询方法只能携带多个参数,而不能携带将着这多个参数进行封装的一个对象。对于这个问题,有两种解决方案。

方案一:将这多个参数封装为一个map

将这多个参数封装为一个Map<String,Object>,根据Map进行查询。

1.dao接口

List<Student> selectStudentByMap(Map<String, Object> map);

2.测试类

@Test
public void test10(){
    Map<String, Object> map = new HashMap<String,Object>();
    map.put("nameCondition", "张");
    map.put("ageCondition",22);

    List<Student> students = dao.selectStudentByMap(map);
    for (Student student : students) {
        System.out.println(student);
    }
}

3.修改映射文件

<select id="selectStudentByMap" resultType="Student">
    select *from student
    where name like '%' #{nameCondition} '%'
    and age > #{ageCondition}
</select>

方案二:多个参数逐个接收

对于mapper中的SQL语句,可以通过参数索引#{index}的方式逐个接收每个参数。

1.dao接口

List<Student> selectStudentByConditions(String name,int age);

2.测试类

@Test
public void test11(){
    List<Student> students = dao.selectStudentByConditions("张", 22);
    for (Student student : students) {
        System.out.println(student);
    }
}

3.映射文件

<select id="selectStudentByconditions" resultType="Student">
    select * from student
    where name like '%' #{0} '%'
    and age > #{1}
</select>

<span style=”font-size:16px;font-weight:bold;”>
摘要:
在mssql中,一条sql语句默认为一个事务,下文展示如何在一条sql语句中,插入多行数据
</span>
<hr />
例:
 

动态SQL

动态sql,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的sql语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的sql语句。此时,可使用动态sql来解决这样的问题

www.350.vip 1

用户自定义查询.PNG

动态sql,即通过MyBatis提供的各种标签对条件作出判断以实现拼接sql语句

这里的条件判断使用的表达式为OGNL表达式。常用的动态SQL标签有<if>、<where>、<choose/>、<foreach>等。

1.实体类:

public class Student {

    private Integer id;
    private String name;
    private int age;
    private double score;
    //无参构造器与带参构造器
    //getter 和 setter
    //toString()
}

2.测试类

public class MyTest {

    private IStudentDao dao;
    private SqlSession session;

    @Before
    public void setUp(){
        session = MyBatisUtils.getSqlSession();
        dao = session.getMapper(IStudentDao.class);
    }

    @After
    public void tearDown(){
        if(session!=null){
            session.close();
        }
    }
}

注意事项:

在mapper的动态sql中若出现大于号(>)、小于号(<)、大于等于号(>=)、小于等于号(<=)等符号,最好将其转换为实体符号。否则,xml可能会出现解析出错问题。

www.350.vip 2

替换规则.PNG

1.<if/>标签

对于该标签的执行,当test的值为true时,会将其包含的sql片段拼接到其后所在的sql语句中。

例:查询出满足用户提交查询条件的所有学生。用户提交的查询条件可以包含一个姓名的模糊查询,同时还可以包含一个年龄的下限。当然,用户在提交表单时可能两个条件均作出了设定,也可能两个条件均不做设定,也可以只做其中一项设定。

查询条件不确定,查询条件依赖于用户提交的内容。此时,就可使用动态sql语句,根据用户提交内容对将要执行的sql进行拼接。

dao接口:

public interface IStudentDao {      
    List<Student> selectStudentsIf(Student student) 
}

映射文件:

<select id="selectStudentsIf" resultType="Student">
    select * from student
    where 1=1
    <if test="name !=null and name!=''">
        and name like '%' #{name} '%'
    </if>
    <if test="age > 0">
        and age > #{age}
    </if>
</select>

测试类:

@Test
public void test01(){
    Student student = new Student();
    List<Student> students = dao.selectStudentsIf(student);
    System.out.println(students);
}

2.<where/>标签

dao接口:

public interface IStudentDao {

    List<Student> selectStudentsIf(Student student);
    List<Student> selectStudentsWhere(Student student);
}

映射文件:

<select id="selectStudentsWhere" resultType="Student">
    select * from student
    <where>
        <if test="name!=null and name!=''">
            and name like '%' #{name} '%'
        </if>
        <if test="age > 0">
            and age > #{age}
        </if>
    </where>
</select>

测试:

@Test
public void test02(){
    Student student = new Student();
    List<Student> students = dao.selectStudentsWhere(student);
    System.out.println(students);
}

3.<choose/>标签

该标签只可以包含<when/><otherwise/>,可以包含多个<when/>与一个<otherwise/>。他们联合使用,完成java中的开关语句switch..case功能。

需求:若姓名不空,则按姓名查询;若姓名为空,则按年龄查询;若没有查询条件,则没有查询结果。

dao接口:

public interface IStudentDao {

    List<Student> selectStudentsIf(Student student);
    List<Student> selectStudentsWhere(Student student);
    List<Student> selectStudentsChoose(Student student);
}

映射文件:

对于<choose/>标签,其会从第一个<when/>开始逐个向后进行条件判断。若出现<when/>中的test属性值为true的情况,则直接结束<choose/>标签,不再向后进行判断查找。若所有<when/>的test判断结果均为false,则最后会执行<otherwise/>标签。

<select id="selectStudentsChoose" resultType="Student">
    select * from student
    <where>
        <choose>
            <when test="name!=null and name!=''">
                and name like '%' #{name} '%'
            </when>
            <when test="age>0">
                and age < #{age}
            </when>
            <otherwise>
                and 1 != 1
            </otherwise>
        </choose>
    </where>
</select>

测试类:

@Test
public void test03(){
    Student student = new Student();
    List<Student> students = dao.selectStudentsChoose(student);
    System.out.println(students);
}

4.<foreach/>标签–遍历数组

<foreach/>标签用于实现对于数组于集合的遍历。对其使用,需要注意:

  • collection表示要遍历的集合类型,这里是数组,即array
  • open、close、separator为对遍历内容的SQL拼接

dao接口:

public interface IStudentDao {

    List<Student> selectStudentsIf(Student student);
    List<Student> selectStudentsWhere(Student student);
    List<Student> selectStudentsChoose(Student student);
    List<Student> selectStudentsForeachArray(Object[] studentIds);
}

映射文件

动态sql的判断中使用的都是OGNL表达式。OGNL表达式中的数组使用array表示,数组长度使用array.length表示。

<select id="selectStudentsForeachArray" resultType="Student">
    select * from student
    <if test="array !=null and array.length >0">
        where id in
        <foreach collection="array" open="(" close=")" item="myid" separator=",">
            #{myid}
        </foreach>
    </if>
</select>

www.350.vip 3

foreach标签.PNG

测试类:

@Test
public void test04(){   
    Object[] studentIds = new Object[]{1,3};
    List<Student> students = dao.selectStudentsForeachArray(studentIds);
    System.out.println(students);
}

5.<foreach/>标签–遍历泛型为基本类型的List

dao接口:

public interface IStudentDao {

    List<Student> selectStudentsIf(Student student);
    List<Student> selectStudentsWhere(Student student);
    List<Student> selectStudentsChoose(Student student);
    List<Student> selectStudentsForeachArray(Object[] studentIds);
    List<Student> selectStudentsForeachList(List<Integer> studentIds);
}

映射文件:

OGNL表达式中的List使用list表示,其大小使用list.size表示。

<select id="selectStudentsForeachList" resultType="Student">
    select * from student
    <if test="list!=null and list.size > 0">
        where id in
        <foreach collection="list"  open="(" close=")" item="myid" separator=",">
            #{myid}
        </foreach>
    </if>
</select>

测试类:

@Test
public void test05(){
    List<Integer> studentIds = new ArrayList<Integer>();
    student.add(1);
    student.add(3);

    List<Student> students = dao.selectStudentsForeachList(studentIds);
    System.out.println(students);   
}

6.<foreach/>标签–遍历泛型为自定义类型的List

dao接口:

List<Student> selectStudentsForeachList2(List<Student> students);

映射文件:

注意,这里的当前遍历对象类型是List中的泛型,即是Student对象。

<select id="selectStudentsForeachList2" resultType="Student">
    <!-- select * from student where id in(1,3) -->
    select * from student
    <if test="list!=null and list.size > 0">
        where id in
        <foreach collection="list"  open="(" close=")" item="stu" separator=",">
            #{stu.id}
        </foreach>
    </if>
</select>

测试类:

@Test
public void test09(){
    Student student1 = new Student();
    student1.setId(1);
    Student student3 = new Student();
    student3.setId(3);

    List<Student> students = new ArrayList<Student>();
    students.add(student1);
    students.add(student3);

    students = dao.selectStudentsForeachList2(students);
    System.out.println(students);
}

7.<sql/>标签

<sql/>标签用于定义sql片段,以便其它sql标签复用。而其他标签使用该SQL片段,需要使用<include/>子标签。该<sql/>标签可以定义SQL语句中的任何部分,所以<include/>子标签可以放在动态sql的任何位置

dao接口:

List<Student> selectStudentsBySQLFragment(List<Student> students);

映射文件:

www.350.vip 4

使用sql片段.PNG

测试类:

@Test
public void test09(){
    Student student1 = new Student();
    student1.setId(1);
    Student student3 = new Student();
    student3.setId(3);

    List<Student> students = new ArrayList<Student>();
    students.add(student1);
    students.add(student3);

    students = dao.selectStudentsBySQLFragment(students);
    System.out.println(students);
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注