SSM框架之Mybatis——多表操作和注解开发

目录

一、多表操作

1.1一对一查询

1.2一对多查询

1.3多对多查询

1.4小结

二、MyBatis注解开发

2.1注解实现增删改查

2.2注解实现复杂映射开发

2.2.1一对一查询的注解开发

2.2.2一对多查询的注解开发

2.2.3多对多查询的注解开发

三、SSM框架整合

3.1原始整合

3.2Spring整合MyBatis


一、多表操作

实际开发中,一个项目通常需要很多张表才能完成。

例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系。

1.1一对一查询

1、一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

从上图我们可以看出orders对应user是一对一的关系,一个订单只能对应有一个用户。

 2、一对一查询代码实现

首先我们新建一个订单实体类Order,

class Order {
    private int id;//订单号
    private Date orderTime;//下单时间
    private double total;//订单的总金额
    private User user;//表明当前订单属于哪个用户

    ...//此处省略get、set方法和toString方法
}

然后我们给该实体类创建一个OrderMapper接口,里面写一个方法,

interface OrderMapper {
    public List<Order> findAll();
}

然后根据接口定义的返回值和方法名,对OrderMapper.xml进行配置,

<?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">

<!--指定sql语句的命名空间-->
<mapper namespace="Mapper.OrderMapper">
    <resultMap id="orderMap" type="order">
        <!--手动指定字段与实体属性的映射关系
            column:数据表的字段名称
            property:实体的属性名称
            主键用id标签进行关系配置,其他属性用result进行配置
        -->
        <id column="oid" property="id"></id>
        <result column="ordertime" property="orderTime"></result>
        <result column="total" property="total"></result>
        <result column="uid" property="user.id"></result>
        <result column="username" property="user.username"></result>
        <result column="password" property="user.password"></result>
        <result column="birthday" property="user.birthday"></result>
    </resultMap>


    <select id="findAll" resultMap="orderMap">
        SELECT o.id oid,o.ordertime,o.total,u.id uid,u.username,u.password,u.birthday FROM orders o,USER u WHERE o.uid=u.id
    </select>
</mapper>

这里我们对返回值类型重新指定了一个集合类型orderMap,里面手动制定了字段和实体属性的映射关系。(不指定的话则框架不会帮我们给Order实体中的user对象进行赋值)

我们还可以使用association标签给Order实体中的user对象进行关系指定,

<resultMap id="orderMap" type="order">
    <id column="oid" property="id"></id>
    <result column="ordertime" property="orderTime"></result>
    <result column="total" property="total"></result>
    <!--通过association标签指定Order实体中的user对象为Domain.User类-->
    <association property="user" javaType="user">
        <id column="uid" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="birthday" property="birthday"></result>
    </association>
</resultMap>

接着我们进行测试,

@Test
public void test1() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
    List<Order> orderList = orderMapper.findAll();
    for (Order order : orderList) {
        System.out.println(order);
    }
}

1.2一对多查询

1、一对多查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

从上图我们可以看出user对应orders是一对多的关系,一个用户可以有多个订单。

首先我们要在User实体类中定义好对应的属性,包括订单的信息,

class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;
    private List<Order> orderList;//当前用户存在哪些订单

    //省略了set、get方法和toString方法
}

接着定义一个UserMapper接口,里面写一个方法

interface UserMapper {
    public List<User> findAll();
}

然后根据接口的方法,写UserMapper.xml文件,配置好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">

<!--指定sql语句的命名空间-->
<mapper namespace="Mapper.UserMapper">
    <resultMap id="userMap" type="user">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
        <!--配置集合信息,property集合名称,ofType代表当前集合中的数据类型-->
        <collection property="orderList" ofType="order">
            <id column="oid" property="id"/>
            <result column="ordertime" property="orderTime"/>
            <result column="total" property="total"/>
        </collection>
    </resultMap>

    <select id="findAll" resultMap="userMap">
        SELECT u.id,u.username,u.password,u.birthday,o.id oid,o.ordertime,o.total FROM USER u,orders o WHERE u.id=o.uid
    </select>
</mapper>

这里我们使用的是collection标签对User实体中的order对象进行赋值,

然后进行测试,

@Test//一对多查询
public void test2() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = userMapper.findAll();
    for (User user : userList) {
        System.out.println(user);
    }
}

1.3多对多查询

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色

从上图和看出user和role之间为多对多关系。

首先哦我们要在数据库中建立好三个表,以及他们的主键和外键关系。

然后我们新建一个role实体类,里面定义属性以及对应的set、get方法和toString方法。

class Role {
    private int id;
    private String roleName;
    private String roleDesc;

    //省略了set、get方法和toString方法
}

我们还要在User的实体类中加入role的信息,

public class User {
    private int id;
    private String username;
    private String password;
    private Date birthday;

    private List<Order> orderList;//当前用户存在哪些订单
    private List<Role> roleList;//当前用户具备哪些角色

    //省略set、get方法和toString方法,这里自己生成一下
}

然后在UserMapper接口中定义一个新的方法,用于查询用户和角色信息,

public List<User> findUserRole();

接着在UserMapper.xml中根据接口的方法进行配置,

<?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">

<!--指定sql语句的命名空间-->
<mapper namespace="Mapper.UserMapper">
    <resultMap id="userRoleMap" type="user">
        <id column="userid" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
        <!--配置集合信息,property集合名称,ofType代表当前集合中的数据类型-->
        <collection property="roleList" ofType="role">
            <id column="roleid" property="id"/>
            <result column="rolename" property="roleName"/>
            <result column="roleDesc" property="roleDesc"/>
        </collection>
    </resultMap>

    <select id="findUserRole" resultMap="userRoleMap">
        SELECT * FROM USER u,user_role ur,role r WHERE u.id=ur.userid AND ur.roleid=r.id
    </select>
</mapper>

然后我们进行测试,

@Test//多对多查询
public void test3() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = userMapper.findUserRole();
    for (User user : userList) {
        System.out.println(user);
    }
}

1.4小结

MyBatis多表配置方式

  • 一对一配置:使用<resultMap>做配置
  • 一对多配置:使用<resultMap>+<collection>做配置
  • 多对多配置:使用<resultMap>+<collection>做配置

二、MyBatis注解开发

我们知道在MyBatis指定sql语句时,用到的是xml配置的方法,那么同样我们也可以用注解配置。

这几年来注解开发越来越流行,MyBatis也可以使用注解开发方式,这样我们就可以减少编写Mapper 映射文件了。

下面是MyBatis中常用的一些注解:

  • @Insert:实现新增
  • @Update:实现更新
  • @Delete:实现删除
  • @Select:实现查询
  • @Result:实现结果集封装
  • @Results:可以与@Result 一起使用,封装多个结果集
  • @One:实现一对一结果集封装
  • @Many:实现一对多结果集封装

我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

2.1注解实现增删改查

xml配置实现我们都已经比较了解了,就是先定义接口,然后写xml配置文件,给接口中的方法映射对应的sql语句,最后执行。

使用注解的方式的话就可以不使用mapper.xml来配置sql语句和对应的方法之间的关系了,我们直接在接口定义的方法上用注解来配置对应的sql语句。

interface UserMapper {
    @Insert("insert into user(id,username,password) values (#{id},#{username},#{password})")
    public void insertUser(User user);

    @Update("update user set username=#{username},password=#{password} where id=#{id}")
    public void updateUser(User user);

    @Delete("delete from user where id=#{id}")
    public void deleteUser(int id);

    @Select("select * from user")
    public List<User> findAll();

    @Select("select * from user where id=#{id}")
    public User findById(int id);
}

此外,我们还需要在sqlMapConfig核心配置文件中加载我们定义的映射关系,

<!--加载映射关系-->
<mappers>
    <!--指定接口所在的包-->
    <package name="Mapper"/>
</mappers>

然后我们进行测试,这里我们为了方便测试,将用于获取usermapper对象的代码抽取出来,使用AOP思想将这段代码作为前置通知,在每个测试方法执行之前执行,

private UserMapper userMapper;

@Before
public void before() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");//获取配置文件输入流
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);//获取session工厂对象
    SqlSession sqlSession = sqlSessionFactory.openSession(true);//获取session对象,并设置事务为自动提交
    userMapper = sqlSession.getMapper(UserMapper.class);
}

然后我们测试一下插入操作,

@Test//插入操作
public void test1(){
    User user=new User();
    user.setUsername("annotationTest");
    user.setPassword("123");
    userMapper.insertUser(user);
}

 同样的其他增删改查操作也是可以成功运行的。

@Test//修改操作
public void test2(){
    User user=new User();
    user.setId(4);
    user.setUsername("annotationTest");
    user.setPassword("321");
    userMapper.updateUser(user);
}

@Test//删除操作
public void test3(){
    userMapper.deleteUser(4);
}

@Test//根据id查询用户
public void test4(){
    User user = userMapper.findById(2);
    System.out.println(user);
}

@Test//查询所有用户
public void test5(){
    List<User> userList = userMapper.findAll();
    for (User user : userList) {
        System.out.println(user);
    }
}

2.2注解实现复杂映射开发

实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,

而使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置。

注解

说明

@Results

代替的是标签<resultMap>

该注解中可以使用单个@Result注解,也可以使用@Result集合。

使用格式:@Results{@Result(),@Result()})或@Results@Result())

@Result

代替了<id>标签和<result>标签

@Result中属性介绍:

column:数据库的列名

property:需要装配的属性名

one:需要使用的@One 注解(@Resultone=@One)()))

many:需要使用的@Many 注解(@Resultmany=@many)()))

@One(一对一)

代替了<assocation> 标签

是多表查询的关键,在注解中用来指定子查询返回单一对象。

@One注解属性介绍:

select: 指定用来多表查询的 sqlmapper

使用格式:@Result(column=" ",property="",one=@One(select=""))

@Many(多对一)

代替了<collection>标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。

使用格式:@Result(property="",column="",many=@Many(select=""))

2.2.1一对一查询的注解开发

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

首先我们创建两个实体对象User和Order,Order中有一个属性为User对象,代表了当前订单是哪个用户的,该关系为一对一。(因为之前已经生成了User类,所以这里我们只用创建Order实体)

class Order {
    private int id;//订单号
    private Date orderTime;//下单时间
    private double total;//订单的总金额
    private User user;//表明当前订单属于哪个用户

    //省略set、get方法和toString方法,需要自己生成
}

第二步我们使用注解配置Mapper映射关系,创建一个OrderMapper接口,定义一个查询方法,配置好对应的关系,

interface OrderMapper {
    @Select("select *,o.id oid from orders o,user u where o.uid=u.id")
    @Results({
            @Result(column = "oid",property = "id"), //将数据表中oid属性封装到Order对象的id属性中
            @Result(column = "ordertime",property = "orderTime"), //ordertime->orderTime
            @Result(column = "total",property = "total"), //total->total
            @Result(column = "uid",property = "user.id"), //uid->user.id
            @Result(column = "username",property = "user.username"), //username->user.username
            @Result(column = "password",property = "user.password") //password->user.password
    })
    public List<Order> findAll();
}

最后我们进行测试,注意这里我们要修改一下之前用@Before注解写的前置通知的方法,获取OrderMapper的对象,

private OrderMapper orderMapper;

@Before
public void before() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");//获取配置文件输入流
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);//获取session工厂对象
    SqlSession sqlSession = sqlSessionFactory.openSession(true);//获取session对象,并设置事务为自动提交
    orderMapper = sqlSession.getMapper(OrderMapper.class);
}

@Test//一对一查询
public void test1(){
    List<Order> orderList = orderMapper.findAll();
    for (Order order : orderList) {
        System.out.println(order);
    }
}

 我们还有另一种查询语句也可以查到订单及对应的用户信息,利用 @One 标签将Order表中的uid字段提取出来,去查询user表中的数据,并将返回结果封装到Order实体类中的user对象中。

@Select("select * from orders")
@Results({
        @Result(column = "id",property = "id"), //将数据表中oid属性封装到Order对象的id属性中
        @Result(column = "ordertime",property = "orderTime"), //ordertime->orderTime
        @Result(column = "total",property = "total"), //total->total
        @Result(
                property = "user", //指定要封装的属性名称
                column = "uid", //根据哪个字段去查询user表数据,即下面查询语句的参数
                javaType = User.class, //指定封装的实体类型
                one = @One(select = "Mapper.UserMapper.findById") //select属性代表查询哪个接口的方法来获得数据
        )
})
public List<Order> findAll2();

2.2.2一对多查询的注解开发

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

 首先我们要在User实体中加入用户拥有的订单属性,生成对应的set和get方法,

private List<Order> orderList;

这里我们首先要在OrderMapper中写一个根据用户id查询订单信息的方法,方便后面给User实体类中封装订单信息,

@Select("select * from order where uid=#{uid}")
public List<Order> findByUid(int uid);//根据用户id查询对应的订单信息

然后我们在UserMapper中利用注解配置sql语句和方法的对应关系,

@Select("select * from user")
@Results({
        @Result(id=true, column = "id", property = "id"), //id->id,第一个id=true代表当前属性为主键
        @Result(column = "username", property = "username"), //username->username
        @Result(column = "password", property = "password"), //password->password
        @Result(
                column = "id",//将id作为参数进行查询,得到的结果封装到orderList属性中
                property = "orderList",
                javaType = List.class,
                many = @Many(select = "Mapper.OrderMapper.findByUid")//指定查询对应的方法
        )
})
public List<User> findUserOrder();

接着我们进行测试,

@Test//一对多查询
public void test6(){
    List<User> userList = userMapper.findUserOrder();
    for (User user : userList) {
        System.out.println(user);
    }
}

2.2.3多对多查询的注解开发

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色

 首先我们要新建role实体类,

class Role {
    private int id;
    private String roleName;
    private String roleDesc;
    
    //省略了set、get方法和toString方法
}

 然后我们在User实体类中新加入一个属性,记录该用户拥有的角色,同时生成set、get方法。

private List<Role> roleList;//描述用户所对应的角色身份

接着新建一个RoleMapper的接口,定义一个方法,根据userid查询role表中的角色信息,

interface RoleMapper {
    @Select("select * from user u,role r,user_role ur where ur.roleid=r.id and ur.userid=#{uid}")
    public List<Role> findByUId(int uid);
}

然后我们需要在UserMapper接口对sql语句和接口方法进行对应,

@Select("select * from user")
@Results({
        @Result(id=true, column = "id", property = "id"), //id->id,第一个id=true代表当前属性为主键
        @Result(id=true, column = "username", property = "username"), //username->username
        @Result(id=true, column = "password", property = "password"), //password->password
        @Result(
                column = "id", //将id作为参数进行查询,得到的结果封装到roleList属性中
                property = "roleList",
                javaType = List.class,
                many = @Many(select = "Mapper.RoleMapper.findByUId")//根据用户的uid查询角色信息
        )
})
public List<User> findUserRole();

 然后进行测试,

@Test//多对多查询
public void test7(){
    List<User> userList = userMapper.findUserRole();
    for (User user : userList) {
        System.out.println(user);
    }
}

 

三、SSM框架整合

我们学习完了Spring(数据的注入)、SpringMVC(web层)和MyBatis(DAO层),现在我们看看如何进行对这些框架进行整合开发。

其实Spring和SpringMVC属于同一生态的框架,本身就已经给我们整合好了,我们需要做的是将Spring和MyBatis整合起来。

3.1原始整合

首先我们创建一个账户表,存储账户的姓名和存款,

 然后我们创建一个Maven工程,在pom.xml中导入我们需要的jar包坐标,主要包括:

spring-context、aspectjweaver、spring-jdbc、spring-tx、spring-test、spring-webmvc
servlet-api、javax.servlet.jsp-api
mybatis、mybatis-spring、mysql-connector-java、c3p0、junit、jstl

下一步我们创建实体类Account,定义好属性并生成对应的set和get方法,

class Account {
    private Integer id;
    private String name;
    private Double money;

    //...
}

下一步我们开始编写DAO层的Mapper接口,定义帐户的一些操作方法,

interface accountMapper {
    public void save(Account account);//保存账户信息
    public List<Account> findAll();//查询所有账户信息
}

接着我们编写业务层的Service接口及对应的实现,

interface AccountService {
    public void save(Account account);
    public List<Account> findAll();
}

@Service("accountService")
class AccountServiceImpl implements AccountService{

    public void save(Account account){
        try {
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            AccountMapper accountMapper = sqlSession.getMapper(AccountMapper.class);
            accountMapper.save(account);
            sqlSession.commit();//提交事务
            sqlSession.close();//关闭会话
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public List<Account> findAll() {
        try {
            InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();
            AccountMapper accountMapper = sqlSession.getMapper(AccountMapper.class);
            List<Account> accountList = accountMapper.findAll();
            //sqlSession.commit();//查询操作不涉及到数据的更改,所以可以不提交事务
            sqlSession.close();//关闭会话
            return accountList;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

下一步我们编写web层的Controller类,

@Controller
@RequestMapping("/account")
public class AccountController {
    @Autowired//自动注入
    private AccountService accountService;

    //保存
    @RequestMapping("/save")
    @ResponseBody//返回的字符串直接显示在页面上,不进行跳转
    public String save(Account account){
        accountService.save(account);//调用业务层方法
        return "保存成功";
    }

    //查询
    @RequestMapping(value = "findAll")
    public ModelAndView findAll(){
        List<Account> accountList = accountService.findAll();//获取查询用户的数据
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("accountList",accountList);//添加用户集合数据
        modelAndView.setViewName("accountList");//设置要跳转的视图名称
        return modelAndView;
    }
}

接下来我们开始编写界面,分别有添加用户数据页面和展示用户数据的页面,

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>添加账户信息表单</h1>
    <form name="accountForm" action="${pageContext.request.contextPath}/account/save" method="post">
        账户名称:<input type="text" name="name"><br>
        账户金额:<input type="text" name="money"><br>
        <input type="submit" value="保存"><br>
    </form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>展示账户数据列表</h1>
    <table border="2">
        <tr>
            <th>账户id</th>
            <th>账户名称</th>
            <th>账户金额</th>
        </tr>
        <%--循环显示用户数据--%>
        <c:forEach items="${accountList}" var="account">
            <tr>
                <td>${account.id}</td>
                <td>${account.name}</td>
                <td>${account.money}</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

然后是生成需要的配置文件,包括:

1、Spring的核心配置文件:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置组件扫描,扫描service和mapper-->
    <context:component-scan base-package="service"/>
    <context:component-scan base-package="mapper"/>
</beans>

2、SpringMVC的核心配置文件:spring-mvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--组件扫描 主要扫描controller层-->
    <context:component-scan base-package="controller"/>

    <!--配置mvc注解驱动-->
    <mvc:annotation-driven/>

    <!--配置内部资源视图解析器-->
    <bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--开放静态资源访问权限-->
    <mvc:default-servlet-handler/>
</beans>

3、MyBatis的核心配置文件:sqlMapConfig.xml及映射文件mapper.xml

<?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>
    <!--加载jdbc配置文件-->
    <properties resource="jdbc.properties"/>

    <!--自定义别名-->
    <typeAliases>
        <!--扫描包下的所有类,系统为每个类自动生成两个别名(例如Account和account)-->
        <package name="Domain"/>
    </typeAliases>

    <!--配置数据源环境,default指定使用的默认环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <!--加载该包下的所有映射文件-->
        <package name="Mapper"/>
    </mappers>
</configuration>
<?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="mapper.AccountMapper">
    <insert id="save" parameterType="account">
        insert into account values(#{id},#{name},#{money})
    </insert>

    <select id="findAll" resultType="account">
        select * from account
    </select>
</mapper>

4、其他配置文件:web.xml、jdbc.properties、log4j.properties

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--配置Spring监听器-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!--配置SpringMVC的前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--乱码过滤器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb1
jdbc.username=root
jdbc.password=3837
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=debug, stdout

然后我们给项目配置好tomcat服务器启动,

访问 http://localhost:8080/save.js 进行用户信息的添加,

数据库可以看到数据被添加进去了,然后对数据进行查询 http://localhost:8080/account/findAll,

3.2Spring整合MyBatis

上述这种整合方式有很明显的弊端,我们在service层调用dao层方法时,为了获取AccountMapper对象,需要读取mybatis的配置文件,然后获得sqlsession对象,从而调用方法获取对象。

这样每次写方法都需要读配置文件等一系列繁琐操作,我们可以将该对象的创建也交给Spring框架产生。后续的事务控制语句也可以交给Spring容器进行声明式事务控制。

第一步那么首先我们要将SqlSessionFactory工厂对象配置到Spring容器中,

因为SqlSessionFactory工厂对象还需要数据源信息,所以我们将数据源的配置也从sqlMapConfig.xml中引入到Spring的核心配置文件applicationContext.xml中

最后mapper包下的映射接口对象我们也放到Spring的核心配置文件扫描,让框架帮我们创建实现类,并放置到Spring容器中。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--配置组件扫描,扫描service和mapper-->
    <context:component-scan base-package="service"/>
    <context:component-scan base-package="mapper"/>

    <!--加载properties文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置sessionFactory对象-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--给定数据源对象-->
        <property name="dataSource" ref="dataSource"/>
        <!--加载mybatis核心配置文件-->
        <property name="configLocation" value="classpath:sqlMapConfig-spring.xml"/>
    </bean>

    <!--扫描mapper所在的包,并为mapper创建实现类,放置到spring容器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="mapper"/>
    </bean>
</beans>

然后我们的MyBatis的配置文件sqlMapConfig-spring.xml就只剩下了自定别名,

<?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>
    <!--自定义别名-->
    <typeAliases>
        <!--<typeAlias type="domain.Account" alias="account"/>-->
        <!--扫描包下的所有类,系统为每个类自动生成两个别名(例如Account和account)-->
        <package name="domain"/>
    </typeAliases>
</configuration>

最后我们对service层的代码就可以简化,通过自动注入的方式获取mapper的实现类对象,直接调用方法实现业务,

@Service("accountService")
class AccountServiceImpl implements AccountService{
    @Autowired//自动注入的方式获取mapper的实现类对象
    private AccountMapper accountMapper;

    public void save(Account account){
        accountMapper.save(account);
    }

    public List<Account> findAll() {
        return accountMapper.findAll();
    }
}

第二步我们要将事务的控制交给Spring的声明式事务控制,我们在Spring核心配置文件中进行事务的配置,

<!--配置声明式事务控制-->
<!--平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--配置事务增强-->
<tx:advice id="txAdvice">
    <tx:attributes>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!--事务的aop织入-->
<aop:config>
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* service.*.*(..))"/>
</aop:config>

然后测试保存操作,可以看到数据库中数据已经写入了。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值