-
面向接口编程的好处: 1.解决一下四种不规范问题查看全部
-
Mybatis特点: 1.SQL语句与代码分离 优点:便于管理和维护 缺点:不便于调试,需要借助日志工具获得信息 2.用标签控制动态SQL的拼接 优点:用标签代替编写逻辑代码 缺点: 拼接复杂SQL语句时,没有代码灵活,比较复杂 3. 结果集与Java对象的自动映射 优点:保证名称相同即可自动映射 缺点:对开发人员所写的SQL依赖性很强 4. 编写原生SQL 优点:接近JDBC,很灵活 劣势:对SQL语句依赖程序很高查看全部
-
相关代码——(下): /** * 通过MyBatis方式批量新增 */ public void insertBatchByMyBatis(List<CommandContent> contentList) { DBAccess dbAccess = new DBAccess(); SqlSession sqlSession = null; try { sqlSession=dbAccess.getSqlSession(); //通过sqlSession执行SQL语句 ICommandContent commandContent = sqlSession.getMapper(ICommandContent.class); commandContent.insertBatch(contentList); sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if(sqlSession!=null){ sqlSession.close(); } } } }查看全部
-
相关代码——(中): @CommandContentDao.java /** * 和command_content表相关的数据库操作 */ public class CommandContentDao { /** * 通过JDBC方式批量新增 */ public void insertBatchByJDBC(List<CommandContent> contentList) { try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection( "jdbc:mysql://127.0.0.1:3306/micro_message", "root", "."); String inserSql = "insert into commandcontent(content,commandId) values(?,?)"; PreparedStatement pstmt = conn.prepareStatement(inserSql); for (CommandContent content : contentList) { pstmt.setString(1, content.getContent()); pstmt.setInt(2, Integer.valueOf(content.getCommandId())); // pstmt.executeUpdate();//方法1(不推荐) pstmt.addBatch();// 方法2 } pstmt.executeBatch();// 方法2(推荐) } catch (Exception e) { e.printStackTrace(); } }查看全部
-
相关代码——(上): @CommandContent.xml <insert id="insertOne" parameterType="com.imooc.bean.CommandContent"> insert into COMMAND_CONTENT(CONTENT,COMMAND_ID) values(#{content},#{commandId}) </insert> <insert id="insertBatch" parameterType="java.util.List"> insert into commandcontent(content,commandId) values <foreach collection="list" item="item" separator=","> (#{item.content},#{item.commandId}) </foreach> </insert> @ICommandContent.java public interface ICommandContent { /** * 单条新增 */ public void insertOne(CommandContent content); /** * 批量新增 */ void insertBatch(List<CommandContent> contentList); } Ps1:注意:批量新增不同的SQL有不同的语法。(这里针对MySQL) Ps2:separator=",":会加在中间,不会加在头尾。查看全部
-
其他相关代码: @Message.xml <select id="queryMessageListByPage" parameterType="java.util.Map" resultMap="MessageResult"> select <include refid="columns"></include> from MESSAGE <where> <if test="message.command != null and !"".equals(message.command.trim())"> and COMMAND=#{message.command} </if> <if test="message.description != null and !"".equals(message.description.trim())"> and DESCRIPTION like '%' #{message.description} '%' </if> </where> order by ID </select> @Configuration.xml <plugins> <!-- <plugin interceptor="com.imooc.interceptor.PageInterceptor" ></plugin> 如果不需要初始化参数(setProperties()),则直接这条语句即可 --> <plugin interceptor="com.imooc.interceptor.PageInterceptor"> <property name="test" value="abc"></property> </plugin> </plugins> Ps:一个拦截器对应一个<plugin>。查看全部
-
@PageInterceptor.java相关代码——(下): @Override public Object plugin(Object target) { System.out.println(test); return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { this.test=properties.getProperty("test"); } } Ps1:执行顺序:setProperties-->plugin-->[intercept] Ps2:若因为某些原因获取不到想要调用的方法等,可以利用反射思想获取。 Ps3: 两个特殊的符号'^'和'$'。他们的作用是分别指出一个字符串的开始和结束。例子如下: "^The":表示所有以"The"开始的字符串("There","The cat"等); "of despair$":表示所以以"of despair"结尾的字符串; "^abc$":表示开始和结尾都是"abc"的字符串——呵呵,只有"abc"自己了; "notice":表示任何包含"notice"的字符串。 附:"ab+":表示一个字符串有一个a后面跟着至少一个b或者更多。查看全部
-
@PageInterceptor.java相关代码——(中): if(id.matches(".+ByPage$")){ BoundSql boundSql=statementHandler.getBoundSql(); //原始的SQL语句,但是当中的#{}改为? String sql=boundSql.getSql(); //查询总条数的SQL语句 String countSql="select count(*) from ("+sql+")a"; Connection conn=(Connection) invocation.getArgs()[0]; PreparedStatement countStatement= conn.prepareStatement(countSql); /** * 解决当中的#{}改为?后的参数传递问题 */ ParameterHandler parameterHandler=(ParameterHandler) metaObject.getValue("delegate.parameterHandler"); parameterHandler.setParameters(countStatement); ResultSet rs=countStatement.executeQuery(); //获取的是Dao层中的“parameter”参数 Map<?, ?> parameter=(Map<?, ?>) boundSql.getParameterObject(); Page page=(Page) parameter.get("page"); if(rs.next()){//因为只有一条数据,所以不需要while循环 page.setTotalNumber(rs.getInt(1)); } //改造后带分页查询的SQL语句 String pageSql=sql+" limit "+page.getDbIndex()+","+page.getDbNumber(); metaObject.setValue("delegate.boundSql.sql", pageSql); } return invocation.proceed(); }查看全部
-
@PageInterceptor.java相关代码——(上): @Intercepts({ @Signature(args = { Connection.class }, method = "prepare", type = StatementHandler.class) }) public class PageInterceptor<V, K> implements Interceptor { private String test; @Override public Object intercept(Invocation invocation) throws Throwable { /** * 注解里写的参数封装成invocation,通过invocation获取,最后记得invocation.proceed()返回以上操作的代理对象并继续执行。 */ //getTarget():return Plugin.wrap(target, this); StatementHandler statementHandler=(StatementHandler) invocation.getTarget(); //通过反射获取对象 MetaObject metaObject=MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); //通过RoutingStatementHandler中的delegate匹配对应的BaseStatementHandler MappedStatement mappedStatement=(MappedStatement) metaObject.getValue("delegate.mappedStatement"); //配置文件中SQL语句的ID String id=mappedStatement.getId();查看全部
-
mybatis的拦截器实现分页(动态代理) 拦截sql语句来实现分页 1.拦截什么样的对象(以page作为参数传入;page对象) 2.拦截对象什么行为 3.什么时候拦截 (在prepareStatement的时候拦截) (源码) 1.RoutingStatementHandler 2.通过RoutingStatementHandler对象的属性delegate找到statement实现类BaseStatementHandler 3.通过BaseStatementHandler类的反射得到对象的MappedStatement对象 4.通过MappedStatement的属性getID得到配置文件sql语句的ID 5.通过BaseStatementHandler属性的到原始sql语句 6.拼接分页sql( 1.需要查询总数的sql 2.通过拦截Connection对象得到PrepareStatement对象 3.得到对应的参数 4.把参数设到prepareStatement对象里的?(该?号在配置文件以#{}形式存在,mybatis会把它转为?号) 5.执行噶sql语句 6.得到总数 ) 7.把属性值为新的sql查看全部
-
关键代码: -->Intercepts.class @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Intercepts { Signature[] value(); } -->Signature.class @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Signature { Class<?> type();//拦截主文件(接口).class String method();//拦截主文件中的方法 Class<?>[] args();//拦截主文件中该方法的参数类型.class } Ps1: Java泛型中的标记符含义: E - Element (在集合中使用,因为集合中存放的是元素) T - Type(Java 类) K - Key(键) V - Value(值) N - Number(数值类型) ? - 表示不确定的java类型 S、U、V - 2nd、3rd、4th types Object跟这些标记符代表的java类型有啥区别呢? Object是所有类的根类,任何类的对象都可以设置给该Object引用变量,使用的时候可能需要类型强制转换,但是用使用了泛型T、E等这些标识符后,在实际用之前类型就已经确定了,不需要再进行类型强制转换。 Ps2:若通过执行plugin()方法,返回本身(不需要代理的对象),则不会执行intercept()方法(因为没有获取代理权);若返回代理对象,则会执行intercept()方法。 Ps3:如果不清楚导入哪个包,可以查看返回类型并点击该类型就可知道是哪个包。查看全部
-
<select id="queryMessageList" parameterType="com.imooc.bean.Message" resultMap="MessageResult"> select <include refid="columns"/> from message <where> <if test="command!=null and !"".equals(command.trim())"> and COMMAND=#{command} </if> </where> </select> //对比上下代码 <select id="queryMessageList" parameterType="java.util.Map" resultMap="MessageResult"> select <include refid="columns"/> from message <where> <if test="message.command!=null and !"".equals(message.command.trim())"> and COMMAND=#{message.command} </if> </where> order by ID limit #{page.dbIndex},#{page.dbNumber} </select> Q1:为何选择java.util.Map?不用实体类? 因为里面代码涉及到两个实体类,所以选择一个它们通用的类型。 Q2:为何选择java.util.Map?不用Lits等之类的? 从parameterType来看字面意思是:参数类型,所以如下代码: parameter.put("message", message); parameter.put("page", page); 传过来的参数parameter来使用。所以接下来的属性前加上message.xxx;page.xxx;(key值对应)。 注意:过早过迟的拦截都不合适。所以在PreparedStatement pstmt=conn.prepareStatement(sql.toString());之前拦截即可(把SQL语句处理再放进去提交)。查看全部
-
@SQL语句里的limit使用方法 SELECT * FROM table LIMIT [offset,] rows rows OFFSET offset 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了上面这样一个功能。 LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1): 为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。 mysql> SELECT * FROM table LIMIT 5,10; //检索记录行6-15 //为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1: mysql> SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last. //如果只给定一个参数,它表示返回最大的记录行数目: mysql> SELECT * FROM table LIMIT 5; //检索前 5 个记录行 //换句话说,LIMIT n 等价于 LIMIT 0,n。 案例: SELECT * FROM table LIMIT 0,5;//0、1、2、3、4 SELECT * FROM table LIMIT 5,5;//5、6、7、8、9 SELECT * FROM table LIMIT 10,5;//10、11、12、13、14查看全部
-
使用原始的方法开发dao时,在具体的实现类中,调用sqlSession.selectList()时需要传递两个参数,根据第一个参数在配置文件中找具体的sql语句,这里需要注意两个风险,①编码中的namespace 与配置文件中的namespace 一致,②编码中引用的id与配置文件中的id也要一致,手写就会有很大的风险,㈢就是第二个参数的问题,selectList方法中传入的参数是object,而配置文件中是一个pojo对象,那么在编写代码的时候,传递的参数是其他的类型,编译器也不会提示错误,只有程序运行起来的时候,才会出错,④还有返回值,编码中是通过泛型来约束list的,至于list中是什么泛型,编译器都是可以通过的,在配置文件中的返回类型使用resultMap来约束的。 规避以上四个风险的手段,mybatis称之为接口是编程,需要遵循以下规范: 1、 类的映射:使用接口类的全限定名作为配置文件的namespace,完成类与配置文件的对应关系。 2、 方法名:接口方法名与配置文件中将要执行的sql语句的id一样,这样就完成了方法调用的映射。 3、 参数类型:接口方法的输入参数类型和配置文件中sql的parameterType的类型相同 4、 返回值类型:接口方法的返回值类型和配置文件的resultMap的类型相同 具体实现方法:①将调用的接口类传给sqlSession.getMapper(IMessage.class)方法,返回类型就是这个传入参数的类型IMessage,但是这个时候就不在是接口,而是一个具体的实现,调用接口的方法,就可以得到与映射文件一一对应的参数类型。查看全部
-
实现拦截器需要实现三个方法:①intercept(Invocation invacation)<br> ② plugin(Object target)方法参数就是被拦截的对象target,返回的就是满足条件的代理类,Plugin.wrap(target,this):this也就是自定义拦截器实例,通过获取注解得到要拦截的类型,比较target的类型与this获取的要拦截的类型是不是一致,如果满足条件就获取代理对象(获得代理权),并执行intercept方法;如果条件不一致,没有获取代理对象的将直接返回(没有获得代理权),不会经过intercept方法。查看全部
举报
0/150
提交
取消