一、连接池
- 连接池的概念:将JDBC的操作进行了封装,合理的管理连接资源,在启动的时候会直接创建连接的对象,需要使用操作数据库的时候,直接拿着已经开启的连接使用即可,可以避免频繁的链接数据库操作,减少IO(磁盘IO和网络IO)的操作,以此减少数据库的连接压力
1.1 C3P0连接池
- 需要导入C3P0的依赖包:数据库的驱动包、C3P0的核心包和C3P0的依赖包
- C3P0的c3p0-config.xml配置文件,要求:文件名称不能修改,并且文件必须放在src目录下
<?xml version="1.0" encoding="utf-8"?><c3p0-config><default-config><!--数据库连接必要的四个参数--><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/db_bank?useUnicode=true&characterEncoding=utf-8</property><property name="user">root</property><property name="password">root</property><!--连接池其他参数的配置--><property name="initialPoolSize">5</property><property name="maxPoolSize">10</property><property name="checkoutTimeout">3000</property></default-config><mysql><!--数据库连接必要的四个参数--><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/db_bank?useUnicode=true&characterEncoding=utf-8</property><property name="user">root</property><property name="password">root</property><!--连接池其他参数的配置--><property name="initialPoolSize">5</property><property name="maxPoolSize">10</property><property name="checkoutTimeout">3000</property></mysql></c3p0-config>
- 用C3P0连接池封装的工具类
public class C3P0Utils {//声明一个数据源对象private static DataSource dataSource = new ComboPooledDataSource("mysql");//获取连接public static Connection getConn(){try {return dataSource.getConnection();}catch (Exception e){e.printStackTrace();}return null;}//关闭资源public static void close(Object...args){try {if(args.length==3 && args[2] != null){ResultSet rs = (ResultSet) args[2];rs.close();}if(args[1] != null){PreparedStatement ps =(PreparedStatement)args[1];ps.close();}if(args[0] != null){Connection conn = (Connection)args[0];conn.close();}}catch (Exception e){e.printStackTrace();}}}
1.2 Druid连接池
- 依赖的jar包:数据库的驱动包、druid的核心包
创建一个properties文件,名字自定义即可
driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/db_bank?useUnicode=true&characterEncoding=utf-8username=rootpassword=root
创建Druid工具类
public class DruidUtils {//声明一个数据源对象private static DataSource dataSource;//使用静态代码块实现加载properties文件static{try {//获取properties文件InputStream in = DruidUtils.class.getClassLoader().getResourceAsStream("db.properties");Properties prop = new Properties();prop.load(in);//将properties对象交给连接池工厂,由工厂创建相应的数据源对象dataSource = DruidDataSourceFactory.createDataSource(prop);}catch (Exception e){e.printStackTrace();}}//创建连接public static Connection getConn(){try {return dataSource.getConnection();}catch (Exception e){e.printStackTrace();}return null;}//关闭资源public static void close(Object...args){try {if(args.length==3 && args[2] != null){ResultSet rs = (ResultSet) args[2];rs.close();}if(args[1] != null){PreparedStatement ps =(PreparedStatement)args[1];ps.close();}if(args[0] != null){Connection conn = (Connection)args[0];conn.close();}}catch (Exception e){e.printStackTrace();}}}
二、Mybatis概念
- Mybatis是一个ORM框架,主要用来Java和数据库操作之间的数据交互,前生ibatis,如果不用Mybatis,操作数据库要么使用原生的JDBC,要么使用连接池。
2.1 原生JDBC中存在的问题
- 问题1:sql语句是直接写在了Java代码中,这种写法称为硬编码
解决:使用mybatis之后,将Java代码和sql语句进行分离,将所有的sql语句抽取出来,配置在xml文件中即可 - 问题2:如果需要向数据库sql语句中拼接条件,需要使用?占位符,仍然属于硬编码
解决:使用mybatis之后,sql语句都在xml文件中,可以使用mybatis提供的输入映射配置,可以自动的将条件和需要的值填充 - 问题3:在原生的jdbc中,结果集需要对ResultSet进行遍历,并且依次拿到里面的值,再set到对应的模型中,及其麻烦的硬编码模式
解决:使用mybaits之后,在执行完sql语句之后,通过输出映射,可以自动的将所有的数据直接填充到模型中
2.2 Mybatis的结构图

2.3 Mybatis的核心组件
- 会话工厂构造器:SqlSessionFactoryBuilder,用来读取核心配置文件并生成工厂对象
- 会话工厂:SqlSessionFactory,作用:用来开启会话
- 会话:SqlSession,用来获取sql语句,并让执行器执行sql语句,拿到结果集
- Mapper代理:sql Mapper代理对象
三、Mybatis入门
3.1 需要依赖的jar包
- 需要数据库的驱动包
- 需要mybatis的核心包
- 需要mybatis的依赖包(工具包和日志包log4j)
3.2 开发Mybatis入门代码
编写核心配置文件:mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--配置数据源环境--><environments default="development"><!--配置指定的数据源环境--><environment id="development"><!--给mybatis配置事务管理方式--><transactionManager type="JDBC" /><!--配置数据源需要的配置数据--><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://127.0.0.1:3306/db_bank?useUnicode=true&characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!--加载单个mapper文件--><mappers><mapper resource=""/></mappers></configuration>
创建POJO类:目前要求POJO类的属性必须和数据库中字段的属性一致
public class User {private int user_id;private String user_name;private double money;public int getUser_id() {return user_id;}public void setUser_id(int user_id) {this.user_id = user_id;}public String getUser_name() {return user_name;}public void setUser_name(String user_name) {this.user_name = user_name;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}@Overridepublic String toString() {return "User{" +"user_id=" + user_id +", user_name='" + user_name + '\'' +", money=" + money +'}';}}
编写单个的Mapper.xml文件,当写好配置文件之后,一定记得到核心配置文件中加载mapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--根目录为mapper标签,需要有属性namespacenamespace:给当前的mapper取一个唯一的名字,用来区别,目前可以自定义在Mapper代理方式之后,namespace有特殊的含义--><mapper namespace="userMapper"><!--需求:根据id值查询用户的数据,结果集只有一条属性:id:给该select标签取一个唯一的标识,目前可以自定义parameterType:输入映射,填写的是输入参数的数据类型resultType:输出映射,填写的是输出映射的数据类型,如果是返回的模型对象,输出映射填写对应模型的全路径名#{value}:用来后续将输入映射的实际参数值,填充在这个位置,相当于?--><select id="queryUserById" parameterType="java.lang.Integer" resultType="com.woniuxy.model.User"><!--编写sql语句-->select user_id,user_name,money from t_user where user_id = #{value}</select></mapper>
编写测试类
public class Test {public static void main(String[] args) throws Exception{//获取核心配置文件,获取的是输入流String path = "mybatis-config.xml";InputStream config = Resources.getResourceAsStream(path);//获取会话工厂SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);//开启会话SqlSession sqlSession = factory.openSession();/*执行sql语句第一个参数:用来关联执行哪一条sql语句,namespace值.id值第二个参数:sql语句需要的实际参数值*/User user = sqlSession.selectOne("userMapper.queryUserById",1);System.out.println(user);}}
3.3 Mybatis的其他其他操作
- 实现模糊查询
需求:查询用户名以“小”开头的用户数据
1)User的POJO类已经创建好了
2)全局配置文件mybatis-config.xml创建好了,不需要再次配置(如果切换了数据库名需要修改URL,如果有新的xxxMapper。xml文件,需要再次加载,在mappers标签里面再增加一个mapper标签)
3)再UserMapper.xml配置文件中新增查询标签
4)测试代码
重点:#{value}和${value}<!-- 需求:根据用户名查询出以"小"开头的用户数据 parameterType:输入映射,输入映射String resultType:输出映射,输出多个User对象,仍然是全路径 --> <select id="queryUserrByName" parameterType="java.lang.String" resultType="com.woniuxy.model.User"> select user_id,user_name,money from t_user where user_name like "${value}%" </select>
public class LikeTest {public static void main(String[] args) throws Exception{//获取工厂对象String path = "mybatis-config.xml";InputStream config = Resources.getResourceAsStream(path);SqlSessionFactory factory = newSqlSessionFactoryBuilder().build(config);//开启会话SqlSession sqlSession = factory.openSession();/*执行sql语句并获取结果集第一个参数:找到指定的select标签,select标签是sql语句,namespace.id*/List<User> userList =sqlSession.selectList("userMapper.queryUserByName","小");System.out.println(userList);}}
1、#{value}:标识占位符替换,不是字符串,大括号中的值可以任意,一般推荐和POJO中的属性名称一致2、${value}:用字符串进行拼接,会有sql注入的危险,一般不推荐使用,大括号中的值只能是value
四、Mybatis的增删改查(MVC开发)
4.1 搭建环境
引入依赖的jar包,包含数据库驱动包,mybatis核心包和mybatis依赖包
- 创建全局配置文件,全局配置文件名称SqlMapConfig.xml,将文件放置在源文件目录下
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--配置环境--><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://127.0.0.1:3306/db_book?useUnicode=true&characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><mappers><!--如果有单个新Mapper.xml文件产生,则引入一个--></mappers></configuration>
- 配置日志文件,日志文件使用log4j,和mybatis的核心配置文件在同一个目录下,并且名字为log4j.properties
# Global logging configurationlog4j.rootLogger=DEBUG, stdout# MyBatis logging configuration...log4j.logger.org.mybatis.example.BlogMapper=TRACE# Console output...log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
- 创建类(model、POJO、domain)
4.2 Mybatis查询操作
- 需求:查询所有的书籍信息
创建一个BookDao接口
public interface BookDao {//定义一个查询所有书籍数据的方法public List<Book> queryAllBook() throws Exception;}
创建BookMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="bookMapper"><!--需求:查询所有的书籍parameterType:输入映射,无resultType:输出映射,Book的实体对象--><select id="queryBook" resultType="com.woniuxy.model.Book">select book_id,book_name,price,author,number from t_book</select></mapper>
创建BookDao的实现类,需要查询到所有的数据
public class BookDaoImpl implements BookDao {/*需要操作数据库*/@Overridepublic List<Book> queryAllBook() throws Exception {//获取工厂String path = "SqlMapConfig.xml";InputStream config = Resources.getResourceAsStream(path);SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);//开启会话SqlSession sqlSession = factory.openSession();//执行List<Book> bookList = sqlSession.selectList("bookMapper.queryBook");//关闭会话sqlSession.close();return bookList;}}
创建Book的service接口
public interface BookService {//查询所有的书籍public List<Book> queryAllBook() throws Exception;}
创建Book的service实现类
public class BookServiceImpl implements BookService {@Overridepublic List<Book> queryAllBook() throws Exception {//调用dao中的方法BookDao bookDao = new BookDaoImpl();List<Book> bookList = bookDao.queryAllBook();return bookList;}}
创建Book的controller类
public class BookController {public static void main(String[] args) {new BookController().queryAllBook();}public void queryAllBook(){try {//创建Service对象BookService bookService = new BookServiceImpl();List<Book> bookList = bookService.queryAllBook();System.out.println(bookList);}catch (Exception e){e.printStackTrace();}}}
4.3 Mybatis新增操作
- 需求:向book表中新增一条数据
编写dao接口中的方法
//新增数据,将book对象传入public int addBook(Book book) throws Exception;
编写Mapper.xml文件
<!--需求:新增一条book的数据parameterType:输入映射,book对象resultType:输出映射,无--><insert id="insertBook" parameterType="com.woniuxy.model.Book">insert into t_book(book_name, price, author, number)value (#{book_name},#{price},#{author},#{number})</insert>
编写dao的实现类
@Overridepublic int addBook(Book book) throws Exception {//创建工厂String path = "SqlMapConfig.xml";InputStream config = Resources.getResourceAsStream(path);SqlSessionFactory factory = newSqlSessionFactoryBuilder().build(config);//开启会话SqlSession sqlSession = factory.openSession();//执行方法,返回值标识数据库中修改的行数,新增标识新增的行数int row = sqlSession.insert("bookMapper.insertBook",book);System.out.println(row);//提交事务sqlSession.commit();//关闭会话sqlSession.close();return row;}
编写Service接口
//新增一条book数据public int addBook(Book book) throws Exception;
编写service实现类
@Overridepublic int addBook(Book book) throws Exception {//调用dao中的方法BookDao bookDao = new BookDaoImpl();int row = bookDao.addBook(book);return row;}
编写controller中的方法
//新增book数据public void addBook(){try {Scanner in = new Scanner(System.in);Book book = new Book();//获取书籍的数据System.out.print("请输入书籍名称");String book_name = in.next();System.out.print("请输入单价:");double price = in.nextDouble();System.out.print("请输入作者:");String author = in.next();System.out.print("请输入数量:");int number = in.nextInt();//将数据封装到book对象中book.setAuthor(author);book.setBook_name(book_name);book.setNumber(number);book.setPrice(price);//创建Service对象BookService bookService = new BookServiceImpl();int row = bookService.addBook(book);if(row > 0){System.out.println("新增成功");}else{System.out.println("新增失败");}}catch (Exception e){e.printStackTrace();}}
在实际开发中,经常需要在新增数据之后,立即获取当前新增数据的主键id值。如果使用了selectKey标签,mybatis会将主键的值映射到传入的对象中,在dao中获取的时候,直接用传入的对象.get主键属性();
<!--需求:新增一条book的数据parameterType:输入映射,book对象resultType:输出映射,无--><insert id="insertBook" parameterType="com.woniuxy.model.Book"><!--在新增之后,立即获取刚刚新增数据的主键keyColumn:指定数据库中作为主键的字段名称keyProperty:在pojo模型中代表主键的属性名称resultType:主键对应的数据类型--><selectKey keyColumn="book_id" order="AFTER"keyProperty="book_id" resultType="java.lang.Integer"> select last_insert_id()</selectKey>insert into t_book(book_name, price, author, number)value (#{book_name},#{price},#{author},#{number})</insert>
4.4 Mybatis修改操作
- 需求:根据id值修改指定书籍的单价
编写dao的接口
//根据书籍的id值,修改单价public int updateBook(Book book) throws Exception;
编写mapper.xml配置文件
<!--需求:根据id值,修改书籍的单价parameterType:输入映射,输入book对象resultType:输出映射,没有--><update id="editBookById" parameterType="com.woniuxy.model.Book"> update t_book set price = #{price} where book_id = #{book_id} </update>
编写dao的实现类
@Overridepublic int updateBook(Book book) throws Exception {//获取工厂String path = "SqlMapConfig.xml";InputStream config = Resources.getResourceAsStream(path);SqlSessionFactory factory = newSqlSessionFactoryBuilder().build(config);//开启会话SqlSession sqlSession = factory.openSession();//执行sql语句int row = sqlSession.update("bookMapper.editBookById",book);//提交会话sqlSession.commit();//关闭会话sqlSession.close();return row;}
编写service接口
//根据书籍的id值修改书籍的单价public int updateBookById(Book book) throws Exception;
编写service的实现类
@Overridepublic int updateBookById(Book book) throws Exception {//调用dao中的方法BookDao bookDao = new BookDaoImpl();int row = bookDao.updateBook(book);return row;}
编写controller中的方法
//修改书籍的单价public void updateBook() throws Exception{Scanner in = new Scanner(System.in);System.out.print("请输入书籍编号:");int book_id = in.nextInt();System.out.print("请输入书籍的单价:");double price = in.nextDouble();Book book = new Book();book.setBook_id(book_id);book.setPrice(price);//创建Service对象BookService bookService = new BookServiceImpl();int row = bookService.updateBookById(book);if(row > 0){System.out.println("修改成功");}else{System.out.println("修改失败");}}
4,5 Mybatis删除操作
- 根据用户的id值删除用户数据
创建UserDao的接口
public interface UserDao {//根据id值删除用户数据public int deleteById(int user_id) throws Exception;}
创建UserMapper.xml配置文件,因为是新建的mapper.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"><mapper namespace="userMapper"><!--需求:根据用户的id值,删除用户的数据parameterType:输入映射,输入用户id值resultType:输出映射,无--><delete id="deleteUser" parameterType="int">delete from t_user where user_id=#{user_id}</delete></mapper>
创建UserDao的实现类
public class UserDaoImpl implements UserDao {@Overridepublic int deleteById(int user_id) throws Exception {//获取工厂String path = "SqlMapConfig.xml";InputStream config = Resources.getResourceAsStream(path);SqlSessionFactory factory = newSqlSessionFactoryBuilder().build(config);//开启会话SqlSession sqlSession = factory.openSession();//执行方法int row = sqlSession.delete("userMapper.deleteUser",1);//提交事务sqlSession.commit();//关闭会话sqlSession.close();return row;}}
创建User的业务层接口
//根据id值删除用户public int deleteUser(int user_id) throws Exception;
创建User的业务层实现类
public class UserServiceImpl implements UserService {@Overridepublic int deleteUser(int user_id) throws Exception {//调用dao中的方法UserDao userDao = new UserDaoImpl();int row = userDao.deleteById(user_id);return row;}}
编写controller
public void deleteUser() throws Exception{Scanner in = new Scanner(System.in);System.out.print("请输入要删除的编号:");int user_id = in.nextInt();UserService userService = new UserServiceImpl();int row = userService.deleteUser(user_id);if(row > 0){System.out.println("删除成功");}else{System.out.println("删除失败");}}
4.6 Junit单元测试
- 需要单独执行的方法,可以使用Junit单元测试,让方法可以脱离主方法直接执行,要求该方法不能有形式参数,要求该方法不能是静态的。
- Junit一般使用的注解有三个
@Test:要单独执行的方法上添加的注解
@Before:在单独执行的方法之前就要执行的注解
@After:在单独执行的方法之后需要执行的注解 - 事例代码
public class JunitTest {@Testpublic void test(){System.out.println("单元测试的方法");}@Beforepublic void before(){System.out.println("之前的方法");}@Afterpublic void after(){System.out.println("之后执行");}}
五、Mapper代理方式
- 新增一个Mapper接口,用Mapper接口替代以前的Dao接口,dao的实现类可以省略,mybatis会自动地完成dao实现类中的方法执行。
- 如果要使用Mapper代理方式实现代码执行,需要遵循以下规则:
1、namespace的值必须式对应的Mapper接口的全路径名
2、id:必须和mapper接口中定义方法的方法名称一致
3、parameterType:必须和mapper接口中定义方法的形式参数数据类型一致
4、resultType:必须和mapper接口中定义的方法的返回值数据类型一致
以根据id值查询用户数据为例:
编写Mapper接口
public interface UserMapper {//根据用户id查询用户的值public User queryUserById(int user_id) throws Exception;}
编写Mapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.woniuxy.mapper.UserMapper"><!--查询所有的用户parameterType:输入映射,用户的id值resultType:输出映射,用户对象public User queryAllUser(int user_id) throws Exception;如果使用mapper代理方式实现,需要遵循以下规则:id:必须和mapper接口中定义方法的方法名称一致parameterType:必须和mapper接口中定义方法的形式参数数据类型一致resultType:必须和mapper接口中定义的方法的返回值数据类型一致--><select id="queryUserById" parameterType="int" resultType="com.woniuxy.model.User">select user_id,user_name,tel,password from t_user where user_id = #{user_id}</select></mapper>
编写Service接口
public interface UserService {//根据id查询用户数据public User queryUserById(int user_id) throws Exception;}
编写Service实现类
public class UserServiceImpl implements UserService {@Overridepublic User queryUserById(int user_id) throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取mapper对象UserMapper userMapper =sqlSession.getMapper(UserMapper.class);//执行接口中的方法User user = userMapper.queryUserById(user_id);//关闭会话sqlSession.close();return user;}}
编写controller
public class UserController {@Testpublic void queryUserById() throws Exception{UserService userService = new UserServiceImpl();User user = userService.queryUserById(2);System.out.println(user);}}
六、Mybatis的配置
6.1 Mybatis配置文件中读取properties文件
在源目录下创建db.properties配置文件,里面用于存放连接数据库的核心数据
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/db_book?useUnicode=true&characterEncoding=utf-8username=rootpassword=root
在Mybatis核心配置文件中,加载db.properties,并且将里面的四个参数读取到xml配置文件中
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--读取properties配置文件--><properties resource="db.properties" /><!--配置环境--><environments default="development"><environment id="development"><!--数据库的事务管理--><transactionManager type="JDBC"/><!--数据源--><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><!--如果有单个新Mapper.xml文件产生,则引入一个--><mapper resource="mapper/BookMapper.xml"></mapper></mappers></configuration>
6.2 设置别名
- 输入映射和输出映射的时候,每次都需要写全路径,给每一个路径取一个别名,之后再使用该类作为输入映射和输出映射的时候,可以直接使用别名即可。
- 设置别名是在mybatis的核心配置文件中设置
方式1:每次给单个模型类设置别名,比较麻烦
方式2:使用包扫描的方式实现别名设置,推荐方式<!--设置别名--><typeAliases><!--type:表示要设置别名的全路径alias:给该路径取得别名--><typeAlias type="com.woniuxy.model.Book" alias="book" /><typeAlias type="com.woniuxy.model.User" alias="user" /></typeAliases>
<typeAliases><!--使用包扫描的方式:要求所有的模型类需要在同一个包下如果使用包扫描,那么别名默认为类名,可以是类名的小驼峰比如:类名Book 别名:Book或者book类名:UserBook 别名:UserBook 或者userBook--><package name="com.woniuxy.model"/></typeAliases>
6.3 使用mapper的包扫描
- 如果开发中使用的是Mapper代理方式,那么可以在mybatis的核心配置文件中,在加载mapper的时候,可以使用包扫描的方式
- 如果使用包扫描,需要遵循两个规则
规则1:mapper接口和mapper.xml必须放在同一个包下
规则2:mapper接口名称和mapper.xml名称必须一致
<mappers><package name = "com.woniuxy.mapper"></package></mappers>
七、输入映射和输出映射
7.1 输入映射
- 输入映射有两种方式:parameterType和parameterMap,如果只有一个参数,写上该参数的数据类型即可,如果需要多个参数,可以选择先将数据封装到对象中,将对象作为输入映射即可。
7.2 输出映射
- 输出映射有两种方式:resultType和resultMap
- resultType输出映射,可以输出一个对象的属性,会将数据直接封装到对象中,resultType输出映射的值是简单类型,要求查询的数据库结果集必须是一行一列的结果集。
- resultMap输出映射,resultMap用在复杂的查询语句里面,它不能作为简单的映射,需要自定义一个resultMap标签,并且对每一个数据做逐一的映射关系
需求:查询所有的书籍数据,用resultMap方式进行输出映射
<!--需求:查询所有的书籍信息,要求使用resultMap输出映射public List<Book> queryBook() throws Exception;--><!--自定义resultMap标签id:表示给给resultMap取一个唯一的标识符type:表示该结果集要输出到哪一个对象对应的模型类全路径,可以使用别名resultMap标签和select标签输出映射关联是通过id值和resultMap值一致进行关联--><resultMap id="queryBookMap" type="Book"><!--id标签:用来映射数据库中主键和属性中代表主键的属性名称映射关系column:数据库中代表主键的字段名称property:模型类中用来代表主键的属性名称--><id column="book_id" property="book_id" /><!--result标签:用来映射数据库中除了主键以外的其他所有字段column:数据库中代表除了主键主键以外的字段名称property:模型类中用来代表除了主键以外的属性名称--><result column="book_name" property="book_name" /><result column="price" property="price" /><result column="author" property="author" /><result column="number" property="number" /></resultMap><select id="queryBook" resultMap="queryBookMap">select book_id,book_name,price,author,number from t_book</select>
总结:在实际开发中,单表查询建议使用resultType输出映射,只要是多表查询,建议使用resultMap,实际开发中,一般情况resultMap居多。
- resultType不能支持延迟加载,而resultMap可以支持延迟加载
八、多表查询
8.1 一对一关系映射
- 需求:根据用户的id查询用户数据及用户信息数据
- 输出映射使用resultType方式进行:输出映射必须是同一个模型类
需要对模型类进行重构
//省略了get和set方法,自己添加public class UserCustom extends User{private int infoId;private int userId;private String realName;private String address;private int height;private double weight;}
编写mapper接口
public interface UserMapper {//根据id值查询用户数据及用户信息数据public UserCustom queryUserAndInfoById(int userId) throws Exception;}
编写mapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.woniuxy.mapper.UserMapper"><!--需求:根据id查询用户数据及用户信息数据public UserCustom queryUserAndInfoById(int userId) throws Exception;--><select id="queryUserAndInfoById" parameterType="int" resultType="UserCustom">select u.user_id,user_name,tel,password,info_id,real_name,address,height,weightfromdb_book.t_user as u join t_info tionu.user_id = ti.user_idwhereu.user_id = #{user_id}</select></mapper>
编写service接口
public interface UserService {//查询用户及用户信心数据public UserCustom queryUserAndInfoById(int userId) throws Exception;}
编写service的实现类
public class UserServiceImpl implements UserService {@Overridepublic UserCustom queryUserAndInfoById(int userId) throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取mapper对象UserMapper userMapper =sqlSession.getMapper(UserMapper.class);UserCustom userCustom =userMapper.queryUserAndInfoById(userId);//关闭会话sqlSession.close();return userCustom;}}
编写controller代码
public class UserController {@Testpublic void queryUserAndInfoById()throws Exception{//获取service对象UserService userService = new UserServiceImpl();UserCustom userCustom =userService.queryUserAndInfoById(2);System.out.println(userCustom);}}
- 映射输出使用resultMap方式(还是一对一)
需要找到主表和附表,主表:t_user表,附表:t_info表
重构pojo的模型类:重构主表的pojo类
//省略了get和set方法public class User {private int userId;private String userName;private String password;private String tel;//在这里声明一个info对象private Info info;}
编写mapper接口
//根据id值查询用户及用户信息的数据public User queryUserAndInfoById2(int userId) throws Exception;
编写mapper.xml配置文件,输出映射使用resultMap
<!--需求:根据id查询用户数据及用户信息数据public User queryUserAndInfoById2(int userId) throws Exception;--><!--自定义resultMap多表查询的时候,type表示映射的主表对应的pojo类的全路径,可以使用别名 --><resultMap id="queryUserAndInfoById2Map" type="User"><!--多表查询(这里是一对一),首先关联主表和pojo类的映射关系--><!--id标签:表示主表中用主键和主键对应的pojo类中属性的关联映射column:数据库中主表代表主键的字段property:属性中代表主键的属性名称--><id column="user_id" property="userId"/><!--主表中的其他字段,用result标签进行关联映射column:数据库中对应的字段名称property:属性中对应的属性名称--><result column="user_name" property="userName" /><result column="tel" property="tel" /><result column="password" property="password" /><!--关联附表中的属性和字段映射,因为是一对一的关系映射,因此使用标签associationproperty:主表对应的pojo类中声明的附表pojo类对象简单User类中的info对象 javaType:附表对应的pojo类全路径,可以适应别名,info对象对应的全路径--><association property="info" javaType="Info"><!--重复主表中的操作,分别将主键和普通字段与pojo类的属性进行关联映射--><id column="info_id" property="infoId" /><result column="user_id" property="userId" /><result column="real_name" property="realName" /><result column="address" property="address" /><result column="height" property="height" /><result column="weight" property="weight" /></association></resultMap><select id="queryUserAndInfoById2" parameterType="int" resultMap="queryUserAndInfoById2Map">select u.user_id,user_name,tel,password,info_id,real_name,address,height,weightfromdb_book.t_user as u join t_info tionu.user_id = ti.user_idwhereu.user_id = #{user_id}</select>
编写service接口
//查询用户及用户信息数据public User queryUserAndInfoById2(int userId) throws Exception;
编写service实现类
@Overridepublic User queryUserAndInfoById2(int userId) throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取mapper对象UserMapper userMapper =sqlSession.getMapper(UserMapper.class);User user = userMapper.queryUserAndInfoById2(userId);//关闭会话sqlSession.close();return user;}
编写conotroller中的代码
@Testpublic void queryUserAndInfoById2()throws Exception{//获取service对象UserService userService = new UserServiceImpl();User user = userService.queryUserAndInfoById2(2);System.out.println(user);}
8.2 一对多关系映射
- 需求:根据用户id值,查询用户数据及用户对应的订单数据
- 主表:用户表,附表:订单表
对User表进行重构
//这里省略了get和set方法public class User {private int userId;private String userName;private String password;private String tel;//在这里声明一个Order对象的集合private List<Order> orderList;}
编写mapper接口
//根据用户的id值,查询用户数据及用户购买的订单数据public User queryUserAndOrderById(int userId) throws Exception;
编写mapper.xml配置文件
<!--需求:根据用户的id值,查询用户数据及用户购买的订单数据public User queryUserAndOrderById(int userId) throws Exception;--><!--自定义resultMap--><resultMap id="queryUserAndOrderByIdMap" type="User"><!--先映射主表关联--><id column="user_id" property="userId" /><result column="user_name" property="userName"/><result column="tel" property="tel"/><result column="password" property="password"/><!--关联附表的映射关系,这里是一对多的关系,collection标签--><collection property="orderList" ofType="Order"><id column="order_id" property="orderId" /><result column="user_id" property="userId" /><result column="create_time" property="createTime" /><result column="note" property="note" /></collection></resultMap><select id="queryUserAndOrderById" parameterType="int" resultMap="queryUserAndOrderByIdMap">select tu.user_id,user_name,password,tel,order_id,create_time,note fromdb_book.t_user as tu join t_order tontu.user_id = t.user_idwheretu.user_id = #{userId}</select>
编写service接口
//根据id值查询用户及用户对应的订单数据public User queryUserAndOrderById(int userId) throws Exception;
编写service的实现类
@Overridepublic User queryUserAndOrderById(int userId) throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取mapper对象UserMapper userMapper =sqlSession.getMapper(UserMapper.class);User user = userMapper.queryUserAndOrderById(userId);//关闭会话sqlSession.close();return user;}
编写controller
@Testpublic void queryUserAndOrderById()throws Exception{//获取service对象UserService userService = new UserServiceImpl();User user = userService.queryUserAndOrderById(2);System.out.println(user);}
8.3 多对多关系映射
- 需求:查询出所有用户购买的所有书籍
- 主表:用户表,附表:订单表,订单明细表,书籍表
对pojo类进行重构
1、重构User类public class User {private int userId;private String userName;private String password;private String tel;//需要通过User类找到Order类,声明成order对象的集合private List<Order> orderList;}2、重构Order类public class Order {private int orderId;private int userId;private String createTime;private String note;//声明订单明细,声明detail对象的集合private List<Detail> detailList;}3、重构detail类public class Detail {private int detailId;private int orderId;private int bookId;//声明一个book对象,private Book book;}
编写mapper接口
//查询所有用户的购买的所有商品public List<User> queryUserAndBook() throws Exception;
编写Mapper.xml配置文件
<!--需求:查询所有用户的购买的所有商品public List<User> queryUserAndBook() throws Exception;--><!--自定义resultMap--><resultMap id="queryUserAndBookMap" type="User"><!--关联映射主表user的关系--><id column="user_id" property="userId" /><result column="user_name" property="userName" /><result column="tel" property="tel" /><result column="password" property="password" /><!--关联映射user的模型类中的orderList映射,一对多--><collection property="orderList" ofType="Order"><id column="order_id" property="orderId" /><result column="user_id" property="userId" /><result column="create_time" property="createTime" /><result column="note" property="note"/><!--关联映射order类中的detailList映射,一对多--><collection property="detailList" ofType="Detail"><id column="detail_id" property="detailId" /><result column="order_id" property="orderId" /><result column="book_id" property="bookId" /><!--关联映射detail中的book对象,一对一--><association property="book" javaType="Book"> <id column="book_id" property="bookId" /> <result column="book_name" property="bookName" /><result column="price" property="price" /> <result column="number" property="number" /> <result column="author" property="author" /> </association></collection></collection></resultMap><select id="queryUserAndBook" resultMap="queryUserAndBookMap"> selecttu.user_id,user_name,tel,password, t.order_id,create_time, note,detail_id,tb.book_id,book_name,price,author,number fromdb_book.t_user tujoint_order t on tu.user_id = t.user_idjoint_detail td on t.order_id = td.order_idjoint_book tb on td.book_id = tb.book_id ;</select>
编写service接口
//查询所有用户的购买的所有商品public List<User> queryUserAndBook() throws Exception;
编写service实现类
@Overridepublic List<User> queryUserAndBook() throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取mapper对象UserMapper userMapper =sqlSession.getMapper(UserMapper.class);List<User> userList = userMapper.queryUserAndBook();//关闭会话sqlSession.close();return userList;}
编写controller
@Testpublic void queryUserAndBook()throws Exception{//获取service对象UserService userService = new UserServiceImpl();List<User> userList = userService.queryUserAndBook();System.out.println(userList);}
九、动态SQL
9.1 多条件查询
需求:根据传入的数据个数,进行分条件的查询
创建Mapper接口
//根据用户的部分条件进行筛选,将user对象作为形式参数public List<User> queryUser(User user) throws Exception;
创建Mapper.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.woniuxy.mapper.UserMapper"><!--需求:根据用户的部分条件进行筛选,将user对象作为形式参数public List<User> queryUser(User user) throws Exception;--><select id="queryUser" parameterType="User" resultType="User">selectti.user_id, user_name, tel, password, age, info_id, real_name,address, height, weightfromt_user join t_info tiont_user.user_id = ti.user_id<where><if test="age != null and age != ''">and age < #{age}</if><if test="info.address != null">and address = #{info.address}</if></where></select></mapper>
编写service的接口
//根据不同的条件查询用户数据public List<User> queryUser(User user) throws Exception;
编写service实现类
public class UserServiceImpl implements UserService {@Overridepublic List<User> queryUser(User user) throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取Mapper对象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<User> userList = userMapper.queryUser(user);//关闭会话sqlSession.close();return userList;}}
编写controller
public class UserController {@Testpublic void queryUser() throws Exception{User user = new User();//比如:根据地址和年龄进行匹配user.setAge(18);Info info = new Info();info.setAddress("重庆");user.setInfo(info);UserService userService = new UserServiceImpl();List<User> userList = userService.queryUser(user);System.out.println(userList);}}
十、延迟加载
10.1 延迟加载的概念
也叫做懒加载或者按需加载,可以将多表查询用子查询的方式进行拆分,拆分成几个独立的单表查询,需要哪些 数据,只查询需要的即可,如果需要进一步的数据展示,再进行数据库的查询。
10.2 举例说明
mybaits框架默认加载为积极加载,如果要用到延迟加载,需要再核心配置文件中开启延迟加载
<!--开启延迟加载--><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/>
根据需求,开发一个,满足延迟加载的代码,编写Mapper接口
//查询出所有用户的数据及对应用户的订单数据public List<User> queryUserAndOrder() throws Exception;
检查pojo类,区分出主表:user表,附表:order表
public class User {private int userId;private String userName;private String password;private String tel;private int age;//声明info对象private Info info;//需要通过User类找到Order类,声明成order对象的集合private List<Order> orderList;}
mapper.xml配置文件
<!--需求:查询出所有用户的数据及对应用户的订单数据public List<User> queryUserAndOrder() throws Exception; 要求:使用延迟加载--><!--定义新的查询语句--><select id="queryOrderByUserId" parameterType="int" resultType="Order">select order_id, user_id, create_time, note from t_order where user_id = #{user_id}</select><!--自定义resultMap--><resultMap id="queryUserAndOrderMap" type="User"><!--主表映射--><id column="user_id" property="userId" /><result column="user_name" property="userName" /><result column="tel" property="tel" /><result column="password" property="password" /><result column="age" property="age" /><!--附表映射,一对多延迟加载新增的两个属性:column:要用于子查询的条件字段select:新的查询语句,值为新的select的id值--><collection property="orderList" ofType="Order" column="user_id" select="queryOrderByUserId"><!--如果是延迟加载,这里空着--></collection></resultMap><select id="queryUserAndOrder" resultMap="queryUserAndOrderMap">select user_id, user_name, tel, password, age from t_user</select>
service接口
//查询所有用户及用户的订单数据public List<User> queryUserAndOrder() throws Exception;
service的实现类
@Overridepublic List<User> queryUserAndOrder() throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取Mapper对象UserMapper userMapper =sqlSession.getMapper(UserMapper.class);List<User> userList = userMapper.queryUserAndOrder();sqlSession.close();return userList;}
controller类
@Testpublic void queryUserAndOrder()throws Exception{UserService userService = new UserServiceImpl();List<User> userList = userService.queryUserAndOrder();//遍历userListfor(int i = 0;i < userList.size();i++){User user = userList.get(0);System.out.println("编号:"+user.getUserId()+",姓名"+user.getUserName());//获取订单对象List<Order> orderList = user.getOrderList();System.out.println(orderList);}}
十一、Mybatis的缓存
在mybatis的框架中,存在一级缓存和二级缓存,mybatis的缓存指的是第一次查询连接数据库实现查询功能,第二次如果是相同的查询语句,则取缓存里面拿数据,不再连接数据库,以此降低数据库的网络IO
11.1一级缓存
在Mybatis框架中,一级缓存默认开始,不再需要程序员做处理,一级缓存的作用范围在一个会话期间 (SqlSession)
现在用一个代码演示缓存,查看日志中是否执行了sql语句来判断是否查询了数据库。
实例代码:
效果1:当两条sql语句在同一个sqlSession之间,并且查询的条件一致,查看结果:日志中查询了数据库多少次
效果2:在一个会话期间,两条查询语句中间新增一条修改的sql语句并提交事务
效果3:(预留)当修改的语句和缓存区里面的数据无关的时候,是否会清空该缓存
@Overridepublic void testCache(User user) throws Exception {//获取工厂SqlSessionFactory factory = FactoryUtil.newInstance();//开启会话SqlSession sqlSession = factory.openSession();//获取Mapper对象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);User u1 = userMapper.queryUserById(user.getUserId());System.out.println("第一次查询:"+u1);User u2 = userMapper.queryUserById(user.getUserId());System.out.println("第二次查询:"+u2);//关闭会话sqlSession.close();}
11.2二级缓存
二级缓存相对于一级缓存范围更大,范围区间在整个mapper区间,二级缓存数据存储位置在硬盘,如果要使用二级缓存,需要被操作的pojo类序列化,mybatis框架不会默认开启二级缓存,需要在核心配置文件中开启二级缓存,并且在对应的mapper配置文件中标识该mapper开启二级缓存。
在核心配置文件中开启二级缓存
<settings><!--开启二级缓存--><setting name="cacheEnabled" value="true"/> </settings>
在mapper中开启二级缓存
<mapper namespace="com.woniuxy.mapper.UserMapper"><!--标识该mapper开启了二级缓存--><cache /></mapper>
对对应的pojo类进行序列化
public class User implements Serializable { ......}
测试
结果1:如果两个一样的查询语句,当开启了二级缓存之后,那么就算不在同一个会话期间,第二次查询还是走的缓存空间
结果2:在两个查询语句之间,做一次更新操作,并提交事务。现象:如果中间有修改操作,则清空缓存,第二次查询走数据库十二、使用注解开发MyBatis应用
MyBatis支持注解开发,可使用注解替代映射器XML文件,但对于同一个映射器接口不能既用注解又用映射器XML文件,否则会导致MyBatis无法确定到底使用哪种方式而报错。
12.1、CURD操作
MyBatis实现CURD操作有对应的注解:@Select,@Update,@Insert,@Delete。
需求:使用注解对t_student进行CURD操作。
创建映射器接口:src/com/wsjy/mapper/StudentMapper2.java ```java public interface StudentMapper2 { /**- 查询所有学生信息
@return / @Select(“select from t_student”) List
findAll(); /**
- 根据学号查询学生信息
@return / @Select(“select from t_student where sid=#{sid}”) Student findStudentBySid(int sid);
/**
- 新增学生
@param student */ @Insert(“insert into t_student values(#{sid},#{sname},#{ssex},#{sage},#{saddress},#{sbirthday},#{cid})”) void addStudent(Student student);
/**
- 根据学号删除学生信息
@param sid */ @Delete(“delete from t_student where sid=#{sid}”) void deleteStudentBySid(int sid);
/**
- 根据学号修改学生信息
- @param student */ @Update(“update t_student set sname=#{sname},ssex=#{ssex} where sid=#{sid}”) void updateStudent(Student student);
}
在测试类中运行以上方法都可正常执行,从运行结果来看,在查询学生信息时,对应的班级和科目信息为null,代表并没有级联查询班级和科目,可使用注解实现级联查询。<a name="VLPBA"></a>#### 12.2、级联MyBatis通过@Results,@Result,@One,@Many来实现级联操作。- @Results:<resultMap>- @Result:<result>,通过id属性来区分<id>(true)和<result>(false或省略不写)- @One:<association>- @Many:<collection>需求:在查询学生信息的同时,级联查询班级和科目信息<br />修改映射器接口:src/com/wsjy/mapper/StudentMapper2.java```javapublic interface StudentMapper2 {....../*** 根据学生编号查询学生信息,级联查询该学生选修的所有科目信息、所属班级信息* @param sid* @return*/@Select({"select * from t_student where sid=#{sid}"})@Results(id = "studentMap",value = {@Result(id = true,property = "sid",column = "sid"),@Result(property = "sname",column = "sname"),@Result(property = "ssex",column = "ssex"),@Result(property = "sage",column = "sage"),@Result(property = "saddress",column = "saddress"),@Result(property = "sbirthday",column = "sbirthday"),@Result(property = "cid",column = "cid"),@Result(property = "classes",column = "cid",one = @One(select = "com.wsjy.mapper.ClassesMapper.findClassByCid",fetchType = FetchType.EAGER)),@Result(property = "subs",column = "sid",many = @Many(select = "com.wsjy.mapper.SubjectMapper.findSubjectsBySid",fetchType = FetchType.LAZY))})Student findStudentBySid(int sid);}
鉴别器也可以使用注解:@TypeDiscriminator,@Case来完成。
从以上案例可以看出,使用注解实质上并没有减少任何配置,只是将映射器XML文件中的配置全部转移到java源文件中来而已,同时造成代码结构混乱,可读性差,SQL语句与java代码严重耦合,程序功能一旦有所变化,必须修改java源码等一系列问题。
12.3、缓存
缓存主要是指二级缓存,因为一级缓存自动开启,可以直接使用。使用注解开启二级缓存,非常简单,只需要在映射器接口上使用@CacheNamespace(blocking = true)即可开启。
@CacheNamespace(blocking = true)public interface StudentMapper2 {......}
12.4、动态SQL
mybatis3中增加了使用注解来配置Mapper的新特性,常用的注解有:
@SelectProvider
@UpdateProvider
@InsertProvider
@DeleteProvider。
以上注解用于Mapper接口的方法上,使用type属性来指定由哪个类来提供SQL语句,使用method属性指定由type属性指定的类中哪个具体的方法提供SQL。
示例:
public interface UserMapper {//指定被@SelectProvider注解的方法使用SqlProvider类的selectUser方法提供的SQL语句@SelectProvider(type = SqlProvider.class, method = "selectUser")@ResultMap("userMap")public User getUser(long userId);}
@SelectProvider注解用于生成查询用的sql语句,有别于@Select注解,@SelectProvide指定一个Class及其方法,并且通过调用Class上的这个方法来获得sql语句。在上例中,获取查询sql的方法是SqlProvider.selectUser。@ResultMap注解用于从查询结果集RecordSet中取数据然后拼装实体bean。
编写SqlProvider方式一
public class SqlProvider {public String selectUser(long userId) {return "select * from user where userId=" + userId;}}
编写SqlProvider方式二
public class SqlProvider{/*** list类型:mapper方法形参和sql构建器方法形参必须同时加@Param注解* @param ids* @return*/public String deleteByIdsSql(@Param("ids") List<Integer> ids){return new SQL(){{DELETE_FROM("t_test");String idStr="";for (int i = 0; i < ids.size(); i++) {if (i<ids.size()-1)idStr+=ids.get(i)+",";elseidStr+=ids.get(i);}WHERE("id in ("+idStr+")");}}.toString();}/*** 单参数:sql构建器方法参数上同时加上@Param注解,* 单参数时,mapper方法参数上可不加@Param注解,但建议加上* @return*/public String selectByIdsSql(@Param("id") Integer id){return new SQL().SELECT("*").FROM("t_goods").WHERE("id="+id).toString();}}
使用第二种方式的优势是将SQL语句进行结构化,层次分明,避免了第一种形式书写复杂SQL时不便于阅读的问题,具体规则可参见mybatis官网: https://mybatis.org/mybatis-3/zh/statement-builders.html
注解实现动态SQL拼接
1、编写Mapper层代码
//type:产生SQL语句的类型 method:类中真正产生SQL语句的方法名@DeleteProvider(type = BuildSQL.class,method = "getSQL")int deleteByCartId(List<Integer> ids);
2、编写Mapper层注解中的方法
public class BuildSQL{/*** 产生SQL语句的方法* 根据传递的参数,动态构建SQL语句* @return*/public String getSQL(List<Integer> ids){SQL sql = new SQL().DELETE_FROM("t_cart");String condition="id in(";//遍历id集合,生成sql条件for (int i = 0; i < ids.size(); i++) {condition+=ids.get(i)+",";}condition = condition.substring(0, condition.length() - 1)+")";sql.WHERE(condition);return sql.toString();}}
其他增、改、查操作类似,请查阅mybatis官网中的java api条目下的注解部分。
注意:
如果只想实现一次删除多条数据库表记录,可以不使用mybatis的方式处理,而在业务层中进行处理:将要删除的id集合遍历,在循环中逐条删除。
