关闭

乱七八糟

928人阅读 评论(0) 收藏 举报

  • 分类: Maven
    132014-08

    下面讲下如何使用Maven来集成Tomcat7。

    1. Maven继承内嵌的Tomcat7,这种方法很简单易用

    先使用Maven创建一个简单的Java Web项目,不会的话,可以参考我上一篇博客,地址:http://my.oschina.net/liangbo/blog/300485,这里就不重申了。

    下面来看下具体的pom.xml的配置:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      
      <groupId>com.liangbo.web</groupId>
      <artifactId>web-demo</artifactId>
      <packaging>war</packaging>
      <version>0.0.1-SNAPSHOT</version>
      
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        
      </dependencies>
    
      <build>
        <!--添加tomcat7 maven插件-->
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
        
        <finalName>web-demo</finalName>
      </build>
    
    </project>

    和上一篇博客相比,只是增加了一个plugin的配置,之后Run As --> Maven build, 在Goals中输入:tomcat7:run。如果是第一次运行的话,会从中央仓库中下载tomcat插件(如果你没有配置私服的话)。

    1)如果build success的话,控制台会打印出该项目访问的路径。

    2) 我默认使用的中央仓库,运行tomcat7:run的时候,发现其中一个jar包org.apache.commons:commons-compress:1.4不能下载,如果有朋友遇到相同的问题的话,可以尝试配置私服。

    我这里直接配置的Maven开源的私服,你可以参考http://maven.oschina.net/help.html。你可以看到上面的控制台输出的信息,控件下载的地址是以http://maven.oschina.net开头。

    我工作开发也是使用这种集成方式,非常的简单,使用Debug As启动的项目,可以热部署,除非你改动了web.xml,那样你必须得重启服务了。


    2. Maven集成独立的Tomcat7(待完成)


    发布于 2年前, 阅读(124) | 评论(0) | 投票(0) | 收藏(0) 阅读全文...
  • 122014-08

    下面来看看如何在Eclipse中使用Maven来新建Java Web项目。

    1. 创建一个Maven项目,File --> New --> Other, 在窗口中选择Maven --> Maven Project,点击Next

    2. 选择项目路径,默认就行

    3. 选择项目骨架,选择maven-archetype-webapp

    4. 输入Group Id,Artifact Id, Package填写war

    5. 点击Finish之后,项目结构如下

    6. 右键项目,点击Properties --> Project Facts, Java选择1.7,Dynamic Web Module选择3.0,出现下面提示Further configuration available...

    7. 点击后,将webContent该成webapp,之后点击OK

    8. 项目结构如下:

    自己新建一个src/test/resources的源文件,

    9. 查看部署程序集,去掉两个test文件夹,test用于测试,不需要部署

    10. pom.xml中添加自己需要的包

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      
      <groupId>com.liangbo.web</groupId>
      <artifactId>web-demo</artifactId>
      <packaging>war</packaging>
      <version>0.0.1-SNAPSHOT</version>
      
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
        
        <dependency>    
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
      </dependencies>
      
      <build>
        <finalName>web-demo</finalName>
      </build>
    </project>

    11. 右键项目,Run As --> Maven install,将打包好的war直接在tomcat上跑。

    发布于 2年前, 阅读(104) | 评论(0) | 投票(0) | 收藏(0) 阅读全文...
  • 262014-05
     MyBatis的XML配置包含了影响MyBatis行为甚深的设置和属性信息。官方XML文档结构如下:

    • configuration
      • properties(属性)
      • settings(配置)
      • typeAliases(类型别名)
      • typeHandlers(类型处理器)
      • objectFactory(对象工厂)
      • plugins(插件)
      • environments(环境集合属性对象)
        • environment(环境子属性对象)
          • transactionManager(事务管理)
          • dataSource(数据源)
      • databaseIdProvider(数据库ID提供者)
      • mappers(映射器)


    Properties
    (属性)

    这些是外部化的, 可替代的属性, 这些属性也可以配置在典型的 Java 属性配置文件中, 或者通过 properties 元素的子元素来传递。例如:

    <properties resource="org/mybatis/example/config.properties">
      <property name="username" value="dev_user"/>
      <property name="password" value="F2Fa3!33TYyg"/>
    </properties>

    其中的属性就可以在整个配置文件中使用,使用可替换的属性来实现动态配置。比如:

    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>

    这个例子中的 usernamepassword 将会由 properties 元素中设置的值来替换。driver url 属性将会从包含进来的 config.properties 文件中的值来替换。这里提供很多配置的选项。
    属性也可以被传递到 SqlSessionBuilder.build()方法中。例如:

    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, props);
    // ... or ...
    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, props);

    如果在这些地方,属性多于一个的话,MyBatis 按照如下的顺序加载它们:

    • 在 properties 元素体内指定的属性首先被读取。
    • 从类路径下资源或 properties 元素的 url 属性中加载的属性第二被读取,它会 覆盖已经存在的完全一样的属性。
    • 作为方法参数传递的属性最后被读取, 它也会覆盖任一已经存在的完全一样的 属性,这些属性可能是从 properties 元素体内和资源/url 属性中加载的。

    因此, 最高优先级的属性是那些作为方法参数的, 然后是资源/url 属性, 最后是 properties 元素中指定的属性。


    Settings(设置)

    这些是极其重要的调整, 它们会修改 MyBatis 在运行时的行为方式。 下面这个表格描述 了设置信息,它们的含义和默认值。

    设置参数

    描述

        有效值

    默认值

    cacheEnabled

    全局范围内启用或禁用缓存配置任何 映射器在此配置下。

        true | false

    true

    lazyLoadingEnabled

    在全范围内启用或禁用延迟加载。禁用时,所有协会将热加载。

        true | false

    true

    aggressiveLazyLoading

    启用时,有延迟加载属性的对象将被完全加载后调用懒惰的任何属性。否则,每一个属性是按需加载。

        true | false

    true

    multipleResultSetsEnabled

    允许或不允许从一个单独的语句(需要兼容的驱动程序)要返回多个结果

        true | false

    true

    useColumnLabel

    使用列标签,而不是列名。在这方面,不同的驱动有不同的行为。参考驱动文档或测试两种方法来决定你的驱动程序的行为如何。

        true | false

    true

    useGeneratedKeys

    允许JDBC支持生成的密钥。兼容的驱动程序是必需的。此设置强制生成的键被使用,如果设置为true,一些驱动会不兼容性,但仍然可以工作。

        true | false

    false

    autoMappingBehavior

    指定MyBatis的应如何自动映射列到字段/属性。NONE自动映射。 PARTIAL只会自动映射结果没有嵌套结果映射定义里面。 FULL会自动映射的结果映射任何复杂的(包含嵌套或其他)。

        NONE, PARTIAL, FULL

    PARTIAL

    defaultExecutorType

    配置默认执行人。SIMPLE执行人确实没有什么特别的。 REUSE执行器重用准备好的语句。 BATCH执行器重用语句和批处理更新。

        SIMPLE REUSE BATCH

    SIMPLE

    defaultStatementTimeout

    设置驱动程序等待一个数据库响应的秒数。

        Any positive integer

    Not Set (null)

    safeRowBoundsEnabled

    允许使用嵌套的语句RowBounds

        true | false

    false

    mapUnderscoreToCamelCase

    从经典的数据库列名A_COLUMN启用自动映射到骆驼标识的经典的Java属性名aColumn

        true | false

    false

    localCacheScope

    MyBatis的使用本地缓存,以防止循环引用,并加快反复嵌套查询。默认情况下(SESSION)会话期间执行的所有查询缓存。如果localCacheScope=STATMENT本地会话将被用于语句的执行,只是没有将数据共享之间的两个不同的调用相同的SqlSession

        SESSION | STATEMENT

    SESSION

    jdbcTypeForNull

    指定为空值时,没有特定的JDBC类型的参数的JDBC类型。有些驱动需要指定列的JDBC类型,但其他像NULLVARCHAROTHER的工作与通用值。

        JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER

    OTHER

    lazyLoadTriggerMethods

    指定触发延迟加载的对象的方法

        A method name list separated by commas

    equals,clone,hashCode,toString

    defaultScriptingLanguage

    指定所使用的语言默认为动态SQL生成。

        A type alias or fully qualified class name.

    org.apache.ibatis.scripting.xmltags.XMLDynamicLanguageDriver

    callSettersOnNulls

    指定如果setter方法或地图的put方法时,将调用检索到的值是null。它是有用的,当你依靠Map.keySet()或null初始化。注意原语(如整型,布尔等)不会被设置为null

        true | false

    false

    logPrefix

    指定的前缀字串,MyBatis将会增加记录器的名称。

        Any String

    Not set

    logImpl

    指定MyBatis的日志实现使用。如果此设置是不存在的记录的实施将自动查找。

        SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

     Not set

    proxyFactory

    指定代理工具,MyBatis将会使用创建懒加载能力的对象。

        CGLIB | JAVASSIST

    CGLIB


    下面是一个完整的setting元素的设置示例:

    <settings>
      <setting name="cacheEnabled" value="true"/>
      <setting name="lazyLoadingEnabled" value="true"/>
      <setting name="multipleResultSetsEnabled" value="true"/>
      <setting name="useColumnLabel" value="true"/>
      <setting name="useGeneratedKeys" value="false"/>
      <setting name="autoMappingBehavior" value="PARTIAL"/>
      <setting name="defaultExecutorType" value="SIMPLE"/>
      <setting name="defaultStatementTimeout" value="25"/>
      <setting name="safeRowBoundsEnabled" value="false"/>
      <setting name="mapUnderscoreToCamelCase" value="false"/>
      <setting name="localCacheScope" value="SESSION"/>
      <setting name="jdbcTypeForNull" value="OTHER"/>
      <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    </settings>


    typeAliases (类型别名) 

    类型别名是为 Java 类型命名一个短的名字。 它只和 XML 配置有关, 只用来减少类完全 限定名的多余部分。例如:

    <typeAliases>
      <typeAlias alias="Author" type="domain.blog.Author"/>
      <typeAlias alias="Blog" type="domain.blog.Blog"/>
      <typeAlias alias="Comment" type="domain.blog.Comment"/>
      <typeAlias alias="Post" type="domain.blog.Post"/>
      <typeAlias alias="Section" type="domain.blog.Section"/>
      <typeAlias alias="Tag" type="domain.blog.Tag"/>
    </typeAliases>

    使用这个配置,"Blog"可以任意用来替代"domain.blog.Blog"所使用的地方。您也可以指定包MyBatis将会搜索bean。例如:

    <typeAliases>
      <package name="domain.blog"/>
    </typeAliases>

    每个bean都可以在domain.blog被发现,如果没有找到注解,将注册使用小写开头的非限定类的bean的名称作为别名。临屋区将为domain.blog.Author被登记author。 如果@Alias注解的类,它的值将被用作别名。请看下面的例子:

    @Alias("author")
    public class Author {
        ...
    }

    对于普通的 Java 类型,有许多内建的类型别名。它们都是大小写不敏感的,由于重载 的名字,要注意原生类型的特殊处理。

    别名 映射的类型
    _byte byte
    _long long
    _short short
    _int int
    _integer int
    _double double
    _float float
    _boolean boolean
    string String
    byte Byte
    long Long
    short Short
    int Integer
    integer Integer
    double Double
    float Float
    boolean Boolean
    date Date
    decimal BigDecimal
    bigdecimal BigDecimal
    object Object
    map Map
    hashmap HashMap
    list List
    arraylist ArrayList
    collection Collection
    iterator Iterator


    typeHandlers (类型处理器)

    无论是 MyBatis 在预处理语句中设置一个参数, 还是从结果集中取出一个值时, 类型处 理器被用来将获取的值以合适的方式转换成 Java 类型。下面这个表格描述了默认的类型处 理器。

    类型处理器

    Java类型

        JDBC类型

    BooleanTypeHandler

    java.lang.Booleanboolean

        任何兼容的布尔值

    ByteTypeHandler

    java.lang.Byte, byte

        任何兼容的数字或字节类型

    ShortTypeHandler

    java.lang.Shortshort

        任何兼容的数字或短整型

    IntegerTypeHandler

    java.lang.Integerint

        任何兼容的数字和整型

    LongTypeHandler

    java.lang.Longlong

        任何兼容的数字或长整型

    FloatTypeHandler

    java.lang.Float, float

        任何兼容的数字或单精度浮点型

    DoubleTypeHandler

    java.lang.Doubledouble

        任何兼容的数字或双精度浮点型

    BigDecimalTypeHandler

    java.math.BigDecimal

        任何兼容的数字或十进制小数类型

    StringTypeHandler

    java.lang.String

        CHAR 和 VARCHAR 类型

    ClobTypeHandler

    java.lang.String

        CLOB 和 LONGVARCHAR 类型

    NStringTypeHandler

    java.lang.String

        NVARCHAR 和 NCHAR 类型

    NClobTypeHandler

    java.lang.String

        NCLOB 类型

    ByteArrayTypeHandler

    byte[]

        任何兼容的字节流类型

    BlobTypeHandler

    byte[]

        BLOB 和 LONGVARBINARY 类型

    DateTypeHandler

    java.util.Date

        TIMESTAMP 类型

    DateOnlyTypeHandler

    java.util.Date

        DATE 类型

    TimeOnlyTypeHandler

    java.util.Date

        TIME 类型

    SqlTimestampTypeHandler

    java.sql.Timestamp

        TIMESTAMP 类型

    SqlDateTypeHandler

    java.sql.Date

        DATE 类型

    SqlTimeTypeHandler

    java.sql.Time

        TIME 类型

    ObjectTypeHandler

    Any

        其他或未指定类型

    EnumTypeHandler

    Enumeration Type

        VARCHAR-任何兼容的字符串类型, 作为代码存储(而不是索引)

    EnumOrdinalTypeHandler

    Enumeration Type

        Any compatible NUMERIC or DOUBLE, as the position is stored (not the code itself).


    你可以重写类型处理器或创建您自己处理不支持的或非标准的类型。要做到这一点,只需继承org.apache.ibatis.type.BaseTypeHandler类和选择性映射新的类型处理器类的JDBC类型。例如:

    // ExampleTypeHandler.java
    @MappedJdbcTypes(JdbcType.VARCHAR)
    public class ExampleTypeHandler extends BaseTypeHandler<String> {
    
      @Override
      public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
      }
    
      @Override
      public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
      }
    
      @Override
      public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
      }
    
      @Override
      public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
      }
    }
    <!-- mybatis-config.xml -->
    <typeHandlers>
      <typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
    </typeHandlers>
    使用这样的类型处理器将会覆盖已经存在的Java的String类型属性和VARCHAR参数及结果的类型处理器。注意MyBatis不会审视数据库元数据的类型来确定的,所以你必须指定,这是一个VARCHAR字段的参数和结果映射到正确的类型处理。由于这样事实是MyBatis直到执行该语句,它不知道的数据类型。
    MyBatis会知道你要处理这个类型处理器通过内省其泛型类型的Java类型,但你可以重写此行为由两个手段:

    (1)添加javaType属性类型处理器的元素(例如:javaType=“String”)
    (2)添加注释类型处理器类指定Java类型的列表,将它与一个@ MappedTypes。此注释将被忽略,如果javaType属性也被指定。

    通过下列两种方式可以指定相关联的JDBC类型:

    (1)添加jdbcType属性到类型处理器的元素(例如:jdbcType为VARCHAR)。
    (2)添加注释联想到指定的JDBC类型列表类型处理器类的一个@MappedJdbcTypes。此注释将被忽略,而jdbcType属性将被指定。

    最后你可以让MyBatis搜索你的类型处理器

    <!-- mybatis-config.xml -->
    <typeHandlers>
      <package name="org.mybatis.example"/>
    </typeHandlers>
    注意当使用JDBC类型自动发现功能时只能被指定的注解。
    您可以
    创建一个能够处理超过一个类通用的的类型处理器 为了这个目的,MyBatis将会作为参数,并通过实际的类构造类型处理器时,接收类添加一个构造。
    //GenericTypeHandler.java
    public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {
    
      private Class<E> type;
    
      public GenericTypeHandler(Class<E> type) {
        if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
        this.type = type;
      }
      ...


    Handling Enums(处理枚举)

    如果你想使用枚举映射,你会需要使用EnumTypeHandler或EnumOrdinalTypeHandler。
    例如,让我们说,我们需要存储的舍入模式,应该用一些数字,如果它需要四舍五入。默认情况下,MyBatis使用EnumTypeHandler的的枚举值转换成自己的名字。
    注意:EnumTypeHandler是在这个意义特殊,它不像其他的处理程序,它并不只是处理一个特定的类,而是任何扩展Enum的类。

    然而,我们可能不希望存储姓名。我们的DBA可能整数代码,而不是坚持。这是一样容易:添加EnumOrdinalTypeHandler到你的配置文件的类型处理器,现在每个与RoundingMode将被映射到一个整数,使用其序数值。

    <typeHandlers>  
      <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>  
    </typeHandlers>
    但是如果你想相同的枚举映射到一个字符串在一个地方和另一个整数?自动映射器会自动使用EnumOrdinalTypeHandler的,所以如果我们想回去使用简单陈旧的普通EnumTypeHandler的,我们必须告诉它,明确设置类型处理程序使用这些SQL语句。(映射文件没有涉及到下一节,因此,如果这是你第一次通过阅读文档,你可能现在想跳过这些但以后会回来了解它的。
    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
    	<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
    		<id column="id" property="id"/>
    		<result column="name" property="name"/>
    		<result column="funkyNumber" property="funkyNumber"/>
    		<result column="roundingMode" property="roundingMode"/>
    	</resultMap>
    
    	<select id="getUser" resultMap="usermap">
    		select * from users
    	</select>
    	<insert id="insert">
    	    insert into users (id, name, funkyNumber, roundingMode) values (
    	    	#{id}, #{name}, #{funkyNumber}, #{roundingMode}
    	    )
    	</insert>
    	
    	<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
    		<id column="id" property="id"/>
    		<result column="name" property="name"/>
    		<result column="funkyNumber" property="funkyNumber"/>
    		<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
    	</resultMap>
    	<select id="getUser2" resultMap="usermap2">
    		select * from users2
    	</select>
    	<insert id="insert2">
    	    insert into users2 (id, name, funkyNumber, roundingMode) values (
    	    	#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
    	    )
    	</insert>
    
    </mapper>
    请注意,这迫使我们使用一个resultMap代替resultType在select语句中。


    objectFactory(对象工厂)


    MyBatis 每次创建结果对象新的实例时, 它使用一个 ObjectFactory 实例来完成。 如果参数映射存在,默认的 ObjectFactory 不比使用默认构造方法或带参数的构造方法实例化目标 类做的工作多。如果你想重写默认的 ObjectFactory,你可以创建你自己的。比如:

    // ExampleObjectFactory.java
    public class ExampleObjectFactory extends DefaultObjectFactory {
      public Object create(Class type) {
        return super.create(type);
      }
      public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) {
        return super.create(type, constructorArgTypes, constructorArgs);
      }
      public void setProperties(Properties properties) {
        super.setProperties(properties);
      }
      public <T> boolean isCollection(Class<T> type) {
        return Collection.class.isAssignableFrom(type);
      }}
    <!-- mybatis-config.xml -->
    <objectFactory type="org.mybatis.example.ExampleObjectFactory">
      <property name="someProperty" value="100"/>
    </objectFactory>

    ObjectFactory接口非常简单。它包含两个创建方法,处理默认构造函数和其他处理带参数构造。最后,setProperties方法可以被用来配置ObjectFactory的。body内的objectFactory元素中定义的属性将被传递给setProperties方法的ObjectFactory实例在初始化之后。


    plugins(插件)

    MyBatis 允许你在某一点拦截已映射语句执行的调用。默认情况下,MyBatis 允许使用 插件来拦截方法调用:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)
    这些类中方法的详细看签名,每一个完整的方法,可用每个MyBatis的释放与源代码来被发现。你应该理解你覆盖方法的行为,假设你正在做的事情不仅仅是监控呼叫。如果您尝试修改或覆盖一个给定的方法的行为,你很可能会打破MyBatis的核心。这是低层次的类和方法,所以使用插件持谨慎态度。

    使用插件是非常简单的,通过他们所提供的力量。简单实现拦截器接口,确保你想拦截的指定签名。

    // ExamplePlugin.java
    @Intercepts({@Signature(
      type= Executor.class,
      method = "update",
      args = {MappedStatement.class,Object.class})})
    public class ExamplePlugin implements Interceptor {
      public Object intercept(Invocation invocation) throws Throwable {
        return invocation.proceed();
      }
      public Object plugin(Object target) {
        return Plugin.wrap(target, this);
      }
      public void setProperties(Properties properties) {
      }
    }
    <!-- mybatis-config.xml -->
    <plugins>
      <plugin interceptor="org.mybatis.example.ExamplePlugin">
        <property name="someProperty" value="100"/>
      </plugin>
    </plugins>
    该插件在上面会拦截所有叫做“update”的方法在Executor实例,这是一个内部负责低层次映射语句的执行对象。
    注意重写配置类: 除了修改MyBatis核心的行为插件,你也可以完全覆盖配置类。简单扩展并覆盖任何方法里面,并把它传递到的sqlSessionFactoryBuilder.build(myConfig)方法的调用。再次提醒,虽然这可能会严重影响MyBatis的行为,所以谨慎使用。


    environments(环境集合属性对象)

    MyBatis的可以配置多个environment。这是有助于您应用到多个数据库的SQL映射为任意数量的原因。例如:你可能会为您的开发,测试和生产环境中有不同的配置。或者,你可能有多个生产数据库,共享相同的架构,你想使用相同的SQL映射。有许多用例。

    一个重要的事情要记住,虽然:虽然您可以配置多种environment,但你只能选择一个SqlSessionFactory对应的实例

    所以,如果你想连接两个数据库,你需要SqlSessionFactory的创建两个实例。三个数据库,你需要三个实例,并依此类推。这真的很容易,要记住:

    1. 每个数据库对应一个SqlSessionFactory

    要指定创建哪种环境,你只需把它传递到SqlSessionFactoryBuilder作为一个可选的参数。接受环境中的两个签名是:

    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment,properties);
    如果环境被忽略,那么默认环境将会被加载,如下进行:
    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
    SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);

    environment元素定义了如何配置环境:

    <environments default="development">
      <environment id="development">
        <transactionManager type="JDBC">
          <property name="..." value="..."/>
        </transactionManager>
        <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>
    请注意这里的关键部分:
    (1)默认的环境ID(例如,default=“development”)。
    (2)的环境ID为每个定义的环境(例如:ID=“development”)。
    (3)事务管理器的配置(如type=“JDBC”)
    (4)数据源配置(例如type=“POOLED”)

    2. 
    事务管理(transactionManager)

    TransactionManager的有两种类型(即类型=“[JDBC|MANAGED]”)中所包含的MyBatis:

    JDBC - 这个配置直接简单使用了JDBC的提交和回滚。它依赖于从数据源的连接来管理事务范围。

    MANAGED - 这个配置几乎没做什么。它从来不提交或回滚一个连接。相反,它让容器管理的整个生命周期的交易(如JEE应用服务器的上下文)。默认情况下,它会关闭连接。然而一些容器并没有想到这一点,因此如果你需要阻止它关闭连接,设置“形象尤其”属性设置为false。例如:
    <transactionManager type="MANAGED">
      <property name="closeConnection" value="false"/>
    </transactionManager>
    注意:如果你打算使用MyBatis与Spring是无需配置任何的TransactionManager,因为Spring模块将覆盖任何先前设置的配置设置自己的。

    TransactionManager的类型都不需要任何属性。但是,它们都是类型别名,所以换句话说,你可以把你自己的完全合格的类名或类型别名,是指你自己的实施的TransacFactory接口,而不是使用它们。

    public interface TransactionFactory {
      void setProperties(Properties props);  
      Transaction newTransaction(Connection conn);
      Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);  
    }
    任何在XML中配置的属性将被传递给setProperties()方法实例化后。您的实现还需要创建一个交易执行,这也是一个非常简单的接口:
    public interface Transaction {
      Connection getConnection() throws SQLException;
      void commit() throws SQLException;
      void rollback() throws SQLException;
      void close() throws SQLException;
    }
    使用这两个接口,你可以完全自定义MyBatis对事务的处理。

    3. 数据源(datasource

    dataSource 元素使用基本的 JDBC 数据源接口来配置 JDBC 连接对象的资源。


    许多MyBatis的应用程序配置数据源的例子中。然而,它不是必需的。虽然实现,为了方便使用延迟加载,这个数据源是必需的。

    有三种内建的数据源类型(即type=“?”):

    (1) UNPOLLED

        这个数据源的实现简单地打开和关闭连接每次请求。虽然它慢一点,这是一个不错的选择,简单的应用程序,不需要及时的可用连接的性能。在此表演区,不同的数据库也不同,所以对一些人来说可能是不太重要的游泳池,这个配置将是理想的。 UNPOOLED的DataSource配置只有五个属性:
    • driver – 这是 JDBC 驱动的 Java 类的完全限定名(如果你的驱动包含,它也不是 数据源类)。
    • url – 这是数据库的 JDBC URL 地址。
    • username – 登录数据库的用户名。
    • password – 登录数据库的密码。
    • defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
    或者,您可以通过数据库驱动程序的属性。要做到这一点,与驱动程序前缀的属性,例如:
    • driver.encoding=UTF8
    这将传递属性编码,UTF8的价值,数据库驱动程序通过的DriverManager.getConnection(URL,driverProperties)方法。

    (2) POOLED

        此实现数据源连接池的JDBC连接对象,以避免初始连接和认证所需的时间来创建一个新的连接实例。这是一个流行的做法,并发Web应用程序,以实现最快的响应。除了向(UNPOOLED)上述物业,也有许多其他属性,可用于配置POOLED的数据源:
    • poolMaximumActiveConnections – 在任意时间存在的活动(也就是正在使用)连 接的数量。默认值:10
    • poolMaximumIdleConnections – 任意时间存在的空闲连接数。
    • poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检查的时间。默认 值:20000 毫秒(也就是 20 秒)
    • poolTimeToWait – 这是给连接池一个打印日志状态机会的低层次设置,还有重新 尝试获得连接, 这些情况下往往需要很长时间 为了避免连接池没有配置时静默失 败)。默认值:20000 毫秒(也就是 20 秒)
    • poolPingQuery – 发送到数据的侦测查询,用来验证连接是否正常工作,并且准备 接受请求。默认是“NO PING QUERY SET” ,这会引起许多数据库驱动连接由一 个错误信息而导致失败。
    • poolPingEnabled – 这是开启或禁用侦测查询。如果开启,你必须用一个合法的 SQL 语句(最好是很快速的)设置 poolPingQuery 属性。默认值:false。
    • poolPingConnectionsNotUsedFor – 这是用来配置 poolPingQuery 多次时间被用一次。 这可以被设置匹配标准的数据库连接超时时间, 来避免不必要的侦测。 默认值: 0(也就是所有连接每一时刻都被侦测-但仅仅当 poolPingEnabled 为 true 时适用)

    (3) JNDI

        这个数据源的实现是为了使用如 Spring 或应用服务器这类的容器, 容器可以集 中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。这个数据源配置只需要两个属 性:
    • initial_context – 这 个 属 性 用 来 从 初 始 上 下 文 中 寻 找 环 境 ( 也 就 是 initialContext.lookup(initial——context) 。这是个可选属性,如果被忽略,那么 data_source 属性将会直接以 initialContext 为背景再次寻找。
    • data_source – 这是引用数据源实例位置的上下文的路径。它会以由 initial_context 查询返回的环境为背景来查找,如果 initial_context 没有返回结果时,直接以初始 上下文为环境来查找。
    和其他数据源配置相似, 它也可以通过名为 “env.” 的前缀直接向初始上下文发送属性。 比如:
    • env.encoding=UTF8
    在初始化之后,这就会以值“UTF8”向初始上下文的构造方法传递名为“encoding” 的属性。


    databaseIdProvider(数据库ID提供者)


        MyBatis的是能够执行不同的语句,这取决于您的数据库供应商。多数据库厂商的支持的基础上的映射语句的databaseID的属性。 MyBatis将会加载与没有databaseId属性相匹配的当前用的databaseID的所有陈述。如果情况,如果发现相同的语句与和的databaseID无后者将被丢弃。为了使多厂商支持的MyBatis-config.xml文件中添加databaseIdProvider如下:
    <databaseIdProvider type="DB_VENDOR" />
    DB_VENDOR实施databaseIdProvider套作为databaseId由DatabaseMetaData:#getDatabaseProductName()返回的字符串。通常字符串太长,不同版本的同一产品也返回不同的值,所以你可能想将它翻译成一个较短的添加属性,比如如下:
    <databaseIdProvider type="DB_VENDOR">
      <property name="SQL Server" value="sqlserver"/>
      <property name="DB2" value="db2"/>        
      <property name="Oracle" value="oracle" />
    </databaseIdProvider>
    当属性类型为DB_VENDOR databaseIdProvider搜索发现在返回的数据库产品名称或“空”的第一个关键,如果没有匹配的属性对应的属性值。在这种情况下,如果getDatabaseProductName()返回“甲骨文公司(DataDirect产品)”的的databaseID将被设置为“oracle”。
    您可以建立您的自己的DatabaseIdProvider,实现接口org.apache.ibatis.mapping.DatabaseIdProvider的MyBatis-config.xml中注册:
    public interface DatabaseIdProvider {
      void setProperties(Properties p);
      String getDatabaseId(DataSource dataSource) throws SQLException;
    }


    mappers(映射器)

    现在MyBatis的行为是配置上面的配置元素,我们已经准备好来定义映射的SQL语句。但首先,我们需要告诉MyBatis在哪里可以找到它们的。 Java不提供一个很好的手段自动发现,在这方面,所以做到这一点的最好办法是简单地告诉MyBatis在哪里可以找到映射文件。您可以使用相对于类路径的资源引用,或文字,完全合格的URL引用(包括file:/ / /URL)。例如:
    <!-- Using classpath relative resources -->
    <mappers>
      <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
      <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
      <mapper resource="org/mybatis/builder/PostMapper.xml"/>
    </mappers>
    <!-- Using url fully qualified paths -->
    <mappers>
      <mapper url="file:///var/mappers/AuthorMapper.xml"/>
      <mapper url="file:///var/mappers/BlogMapper.xml"/>
      <mapper url="file:///var/mappers/PostMapper.xml"/>
    </mappers>
    <!-- Using mapper interface classes -->
    <mappers>
      <mapper class="org.mybatis.builder.AuthorMapper"/>
      <mapper class="org.mybatis.builder.BlogMapper"/>
      <mapper class="org.mybatis.builder.PostMapper"/>
    </mappers>
    <!-- Register all interfaces in a package as mappers -->
    <mappers>
      <package name="org.mybatis.builder"/>
    </mappers>
    这些语句简单告诉了 MyBatis 去哪里找映射文件。其余的细节就是在每个 SQL 映射文 件中了,下面的部分我们来讨论 SQL 映射文件。



发布于 2年前, 阅读(355) | 评论(0) | 投票(0) | 收藏(0) 阅读全文...
  • 242014-05

    大多数网站的内容都存在数据库里,用户通过请求来访问内容。数据库非常的快,有许多技巧能让你优化数据库的速度,使你不浪费服务器的资源。在这篇文章中,我收录了十个优化数据库速度的技巧。

    1. 小心设计数据库


    第一个技巧也许看来理所当然,但事实上大部分数据库的问题都来自于设计不好的数据库结构。

    譬如我曾经遇见过将客户端信息和支付信息储存在同一个数据库列中的例子。对于系统和用数据库的开发者来说,这很糟糕。

    新建数据库时,应当将信息储存在不同的表里,采用标准的命名方式,并采用主键。

    2. 清楚你需要优化的地方


    如果你想优化某个查询语句,清楚的知道这个语句的结果是非常有帮助的。采用 EXPLAIN 语句,你将获得很多有用的信息,下面来看个例子:

    EXPLAIN SELECT * FROM ref_table,other_table WHERE ref_table.key_column=other_table.column;


    3. 最快的 查询语句…是那些你没发送的语句

    每次你向数据库发送一条语句,你都会用掉很多服务器资源。所以在很高流量的网站中,最好的方法是将你的查询语句缓存起来。

    有许多种缓存语句的方法,下面列出了几个:

    AdoDB: AdoDB 是一个 PHP 的数据库简化库。使用它,你可以选用不同的数据库系统(MySQL, PostGreSQL, Interbase 等等),而且它就是为了速度而设计的。AdoDB 提供了简单但强大的缓存系统。还有,AdoDB 拥有 BSD 许可,你可以在你的项目中免费使用它。对于商业化的项目,它也有 LGPL 许可。

    Memcached:Memcached 是一种分布式内存缓存系统,它可以减轻数据库的负载,来加速基于动态数据库的网站。

    CSQL Cache: CSQL 缓存是一个开源的数据缓存架构。我没有试过它,但它看起来非常的棒。

    4. 不要 select 你不需要的

    获取想要的数据,一种非常常见的方式就是采用*字符,这会列出所有的列。

    SELECT * FROM wp_posts;

    然而,你应该仅列出你需要的列,如下所示。如果在一个非常小型的网站,譬如,一分钟一个用户访问,可能没有什么分别。然而如果像 Cats Who Code 这样大流量的网站,这就为数据库省了很多事。

    SELECT title, excerpt, author FROM wp_posts;


    5. 采用LIMIT 

    仅获得某个特定行数的数据是非常常见的。譬如博客每页只显示十篇文章。这时,你应该使用 LIMIT,来限定你想选定的数据的行数。

    如果没有 LIMIT,表有 100,000行数据,你将会遍历所有的行数,这对于服务器来说是不必要的负担。

    SELECT title, excerpt, author FROM wp_posts LIMIT 10;


    6. 避免循环中的查询

    当在 PHP 中使用 SQL 时,可以将 SQL 放在循环语句中。但这么做给你的数据库增加了负担。

    下面的例子说明了“在循环语句中嵌套查询语句”的问题:

      foreach ($display_order as $id => $ordinal) {
    
          $sql = "UPDATE categories SET display_order = $ordinal WHERE id = $id";
    
          mysql_query ($sql);
    
      }

    你可以这么做:

     UPDATE categories
    
          SET display_order = CASE id
    
              WHEN 1 THEN 3           WHEN 2 THEN 4           WHEN 3 THEN 5       END   WHERE


    7. 采用 join 来替换子查询

    程序员可能会喜欢用子查询,甚至滥用。下面的子查询非常有用:

      SELECT a.id,
    
          (SELECT MAX(created)
    
          FROM posts
    
          WHERE author_id = a.id)
    
      AS latest_post FROM authors a

    虽然子查询很有用,但 join 语句可以替换它,join 语句执行起来更快。

      SELECT a.id, MAX(p.created) AS latest_post
    
      FROM authors a
    
      INNER JOIN posts p
    
          ON (a.id = p.author_id)
    
      GROUP BY a.id


    8. 小心使用通配符

    通配符非常好用,在搜索数据的时候可以用通配符来代替一个或多个字符。我不是说不能用,而是,应该小心使用,并且不要使用全词通配符(full wildcard),前缀通配符或后置通配符可以完成相同的任务。

    事实上,在百万数量级的数据上采用全词通配符来搜索会让你的数据库当机。

      #Full wildcard
    
      SELECT * FROM TABLE WHERE COLUMN LIKE '%hello%';
    
      #Postfix wildcard
    
      SELECT * FROM TABLE WHERE COLUMN LIKE  'hello%';
    
      #Prefix wildcard
    
      SELECT * FROM TABLE WHERE COLUMN LIKE  '%hello';


    9. 采用UNION来代替OR

    下面的例子采用 OR 语句来:

    SELECT * FROM a, b WHERE a.p = b.q or a.x = b.y;

    UNION 语句,你可以将 2 个或更多 select 语句的结果拼在一起。下面的例子返回的结果同上面的一样,但是速度要快些:

    SELECT * FROM a, b WHERE a.p = b.qUNION SELECT * FROM a, b WHERE a.x = b.y


    10. 使用索引

    数据库索引和你在图书馆中见到的索引类似:能让你更快速的获取想要的信息,正如图书馆中的索引能让读者更快的找到想要的书一样。

    可以在一个列上创建索引,也可以在多个列上创建。索引是一种数据结构,它将表中的一列或多列的值以特定的顺序组织起来。

    下面的语句在 Product 表的 Model 列上创建索引。这个索引的名字叫作 idxModel

    CREATE INDEX idxModel ON Product (Model);



    发布于 2年前, 阅读(55) | 评论(0) | 投票(0) | 收藏(0) 阅读全文...
  • 192014-05

    1. 通过 show status 了解SQL执行频率


    通过show status可以提供服务器状态信息,可以根据需要显示当前session级别的统计结果和 global级别的统计结果。
    如:显示当前session,show status like "Com_%",全局级别:show global status。
    以下几个参数对 Myisam 和 Innodb 存储引擎都计数:

        1. Com_select 执行 select 操作的次数,一次查询只累加 1 ;
        2. Com_insert 执行 insert 操作的次数,对于批量插入的 insert 操作,只累加一次 ;
        3. Com_update 执行 update 操作的次数;
        4. Com_delete 执行 delete 操作的次数;

    以下几个参数是针对 Innodb 存储引擎计数的,累加的算法也略有不同:
        1. Innodb_rows_read select 查询返回的行数;
        2. Innodb_rows_inserted 执行 Insert 操作插入的行数;
        3. Innodb_rows_updated 执行 update 操作更新的行数;
        4. Innodb_rows_deleted 执行 delete 操作删除的行数;
    通过以上几个参数,可以很容易的了解当前数据库的应用是以插入更新为主还 是以查询操作为主,以及各种类型的 SQL大致的执行比例是多少。
    此外,以下几个参数便于我们了解数据库的基本情况:
        1. Connections 试图连接 Mysql 服务器的次数
        2. Uptime 服务器工作时间
        3. Slow_queries 慢查询的次数

    2. 定位执行效率低的SQL
        

    可以通过以下两种方式定位执行效率较低的 SQL 语句:
    1. 可以通过慢查询日志定位那些执行效率较低的 sql 语句
    在my.ini文件下的mysqld下添加如下代码:
        log-slow-queries=c:/mysql/slowquery.log 
        long_query_time=2 
    上面的配置打开了slow query日志,将会捕获了执行时间超过了2秒的查询,包括执行速度较慢的管理命令(比如OPTIMEZE TABLE),并且记录了没有使用索引的查询。这些SQL,都会被记录到log-slow-queries指定的文件c:/mysql/slowquery.log 文件中。

        2.  使用 show processlist查看当前MYSQL的线程  命令慢查询日志在查询结束以后才纪录,所以在应用反映执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用 show processlist 命令查看当前 MySQL 在进行的线程,包括线程的状态,是否锁表等等,可以实时的查看 SQL 执行情况, 同时对一些锁表操作进行优化。


    3. 通过explain或desc分析低效的SQL

    通过以上步骤查询到效率低的 SQL 后,我们可以通过 explain 或者 desc 获取MySQL 如何执行 SELECT 语句的信息,包括 select 语句执行过程表如何连接和连接 的次序。

    4. MySQL索引

    索引用于快速找出在某个列中有一特定值的行。对相关列使用索引是提高SELECT 操作性能的最佳途径。
    查询要使用索引最主要的条件是查询条件中需要使用索引关键字,如果是多列 索引,那么只有查询条件使用了多列关键字最左边的前缀时( 前缀索引 ),才可以使用索引,否则将不能使用索引。

    下列情况下, Mysql 不会使用已有的索引:
         1、如果 mysql 估计使用索引比全表扫描更慢,则不使用索引。
         2、如果使用  heap表 并且 where 条件中不用=索引列, 其他 > 、 < 、 >= 、 <= 均不使用索引 MyISAM和innodb表使用索引
         3、使用or分割的条件,如果or前的条件中的列有索引,后面的列中没有索引,那么涉及到的索引都不会使用。
         4、如果创建复合索引,如果条件中使用的列不是索引列的第一部分; (不是前缀索引)
         5、如果 like 是以%开始;
         6、对 where 后边条件为字符串的一定要加引号,字符串如果为数字 mysql 会自动转为字符串,但是不使用索引。

    5. 索引的使用情况

      如果索引正在工作, Handler_read_key 的值将很高,这个值代表了一个行被索引值读的次数,很低的值表明增加索引得到的性能改善不高,因为索引并不经常使用。

    Handler_read_rnd_next 的值高则意味着查询运行低效,并且应该建立索引补救。这个值的含义是在数据文件中读下一行的请求数。如果你正进行大量的表扫描, 该值较高。通常说明表索引不正确或写入的查询没有利用索引。
    语法:show status like 'Handler_read%'。

    6. 优化查询语句

    1) 对查询进行优化,应避免全表查询,首先应该考虑在where及order by设计的列上建立索引

    2)
    应尽量避免在 where 子句中对字段进行 null 值判断 否则将导致引擎放弃使用索引而进行全表扫描

      NULL对于大多数数据库都需要特殊处理,MySQL也不例外,它需要更多的代码,更多的检查和特殊的索引逻辑,有些开发人员完全没有意识到,创建表时NULL是默认值,但大多数时候应该使用NOT NULL,或者使用一个特殊的值,如0,-1作为默认值。
        
      不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。 任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。

    3) 应尽量避免在 where 子句中使用!=或<>操作符, 否则将引擎放弃使用索引而进行全表扫描

        
    MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE。 
    可以在LIKE操作中使用索引的情形是指另一个操作数不是以通配符(%或者_)开头的情形。例如:
    SELECT id FROM  t WHERE col LIKE 'Mich%';    -- 这个查询将使用索引,
    SELECT id FROM  t WHERE col  LIKE '%ike';    -- 这个查询不会使用索引。

    4)应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描

    在某些情况下,or条件可以避免全表扫描:
          
        1. where 语句里面如果带有or条件, myisam表能用到索引, innodb不行。
        2. 必须所有的or条件都必须是独立索引

    5)并不是所有索引对查询都有效

    SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

    6) 索引并不是越多越好

      索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

    7)应尽可能的避免更新 clustered 索引数据列

    因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。

    8) 尽量使用数字型字段

    若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

    9) 尽可能的使用 varchar/nvarchar 代替 char/nchar 

    因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

    10) 最好不要使用"*"返回所有: select * from t 

    用具体的字段列表代替"*",不要返回用不到的任何字段。

    7. 优化Order by语句

    MySQL的弱点之一是它的排序。虽然MySQL可以在1秒中查询大约15,000条记录,但由于MySQL在查询时最多只能使用一个索引。因此,如果WHERE条件已经占用了索引,那么在排序中就不使用索引了,这将大大降低查询的速度。我们可以看看如下的SQL语句:
    SELECT * FROM SALES WHERE NAME = “name” ORDER BY SALE_DATE DESC;

    在以上的SQL
    的WHERE子句中已经使用了NAME字段上的索引,因此,在对SALE_DATE进行排序时将不再使用索引。为了解决这个问题,我们可以对SALES表建立复合索引:
    ALTER TABLE SALES DROP INDEX NAME, ADD INDEX (NAME,SALE_DATE)
         
    这样再使用上述的SELECT语句进行查询时速度就会大副提升。但要注意,在使用这个方法时,要确保WHERE子句中没有排序字段,在上例中就是不能用SALE_DATE进行查询,否则虽然排序快了,但是SALE_DATE字段上没有单独的索引,因此查询又会慢下来。


    在某些情况中, MySQL可以使用一个索引来满足 ORDER BY子句,而不需要额外的排序。 where条件和order by使用相同的索引,并且order by 的顺序和索引顺序相同,并且order by的字段都是升序或者都是降序。例如:下列sql可以使用索引。

     SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
     SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC;
     SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
    但是以下情况不使用索引:
     SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC; --order by 的字段混合 ASC 和 DESC
     SELECT * FROM t1 WHERE key2=constant ORDER BY key1; -- 用于查询行的关键字与 ORDER BY 中所使用的不相同
     SELECT * FROM t1 ORDER BY key1, key2; -- 对不同的关键字使用 ORDER BY

    8. Explain/Desc 解释说明

    explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。使用方法,在select语句前加上explain就可以了
    结果分析:
    table |  type | possible_keys | key | key_len  | ref | rows | Extra 

    1)table
        显示这一行的数据是关于哪张表的 
    2)type
        这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为:system、const、eg_reg、ref、ref_or_null、range、indexhe、ALL。
        system:表仅有一行(=系统表)。这是const联接类型的一个特例
        
        const:(PRIMARY KEY或UNIQUE)
            表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。 const表很快,因为它们只读取一次!
            eg: 
    SELECT * from tbl_name WHERE primary_key=1;
        
        eq_reg:key
            
    对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。
            它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。
            eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。

        ref:key
            对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。
            如果使用的键仅仅匹配少量行,该联接类型是不错的。 ref可以用于使用=或<=>操作符的带索引的列。

        ref_or_null:Or Is null
            该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。
        
        range:=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN
            只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。
            当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range:
        
        indexhe:
            该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。
            当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。
        
        ALL:
            对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,
            使得行能基于前面的表中的常数值或列值被检索出。
    3)
    possible_keys
        显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句 
    4)
    key
        实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引
        这种情况下,可以在SELECT语句中使用USEINDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引。
    5)ken_len
        使用的索引的长度。在不损失精确性的情况下,长度越短越好 
    6)ref
        显示索引的哪一列被使用了,如果可能的话,是一个常数 
    7)
    rows 
        MYSQL认为必须检查的用来返回请求数据的行数 (扫描行的数量)
    8)Extra
        该列包含MySQL解决查询的详细信息,这里可以看到的坏的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,结果是检索会很慢。 

    extra列返回的描述的意义: 

    Distinct:
        一旦MYSQL找到了与行相联合匹配的行,就不再搜索了 
    Not exists :
        MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行, 就不再搜索了。下面是一个可以这样优化的查询类型的例子:
        SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
        假定t2.id定义为NOT NULL。在这种情况下,MySQL使用t1.id的值扫描t1并查找t2中的行。如果MySQL在t2中发现一个匹配的行,它知道t2.id绝不会为NULL,并且不再扫描t2内有相同的id值的行。
        换句话说,对于t1的每个行,MySQL只需要在t2中查找一次,无论t2内实际有多少匹配的行。
    Range checked for each Record(index map:#) 
        没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。
        这是使用索引的最慢的连接之一 ,MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
        对前面的表的每个行组合,MySQL检查是否可以使用range或index_merge访问方法来索取行。
        不同的是前面表的所有列值已知并且认为是常量。这并不很快,但比执行没有索引的联接要快得多。
    Using filesort 
        看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。
        它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行 
    Using index 
        列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,
        这发生在对表的全部的请求列都是同一个索引的部分的时候 
    Using temporary 
        看到这个的时候,查询需要优化了。这里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上 
    Using where
        使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题



    发布于 2年前, 阅读(71) | 评论(0) | 投票(0) | 收藏(0) 阅读全文...
  • 232014-04
    今天上班的时候发现有人使用==来比较空串"",本人一直都是使用equals来比较的,所以特意上网查询了一下,有部分内容借鉴网上的blog。

    以下列举10个比较常见的Java字符串问题。

    1. 如何比较字符串,是使用“==”还是使用equals()?

    简单的说,==比较字符串是否引用同一地址,而equals()比较值是否相等。除非需要检查两个字符串是否是同一个对象,否则应该总是使用equals()方法。

    (1) 使用==判断字符串请注意以下五种情况:
    String s1 = "abc";
    String s2 = "abc";
    System.out.println(s1 == s2); // true
      Java对字符串常量提供了缓冲区,缓冲区内的字符串是可以被共享的。
    String s1 = new String("abc");
    String s2 = new String("abc");
    System.out.println(s1 == s2);  // false

      使用构造器创建的字符串都是在缓冲区外面建一个新的。

    String s1 = "abc";
    String s2 = "a";
    String s3 = "bc";
    String s4 = s2 + s3;
    System.out.println(s1 == s4); // false

      Java中字符串的相加其内部是使用StringBuilder类的append()方法和toString()方法来实现的. 而StringBuilder类toString()方法返回的字符串是通过构造函数创建的.

    String s1 = "abc";
    String s2 = "a" + "bc";
    System.out.println(s1 == s2); // true
       其实这里的s2并没有进行字符串相加, 两个双引号形式的字符串常量相加, 在编译的时候直接会被转为一个字符串"abc".
    String str = "abc";
    str.substring(3);
    str.concat("123");
    System.out.println(str == "abc"); // true

      由于字符串是常量(内存中创建对象后不能修改), 该类中所有方法都不会改变字符串的值. 如果希望使用一个可变的字符串, 可以使用StringBuilder或StringBuffer类.


    (2) Java判断字符串是否为空有三种方法:
    a. 使用的人最多,直观方便,但是效率低。

    if (str == null || str.equals(""))

    b. 比较字符串的长度,效率高

    if (str == null || str.length() == 0)
    c. Java SE 6.0才开始使用,效率和b才不多
    if (str == null || str.isEmpty())

    2.  为什么为在处理私密信息的时候,选择char [ ]比String好?

    String是不可改变的。这意味着一旦String对象被创建,那个地址上的值将保持不变,直到垃圾收集器有空来做自动清理。而使用char[ ]可以(在用完后)明确地修改它的元素。这种一来,私密信息(例如密码)就不会在系统的任何地方出现。

    3. 我们可以在switch语句中用String作分支条件吗?

    从JDK 7开始是可以的。我们可以使用String符串作为Switch条件。第JDK 6之前,我们不能使用String作为Switch条件。

    4. 如何转换String为int?

    int n = Integer.parseInt("10");

    5. 如何用空白符分割字符串?

    可以简单地使用正则表达式做分割。“\s"代表所有空格符,如""、 " \ "、 " \ r"、" \ n "。

    String[] strArray = aString.split("\\s+");

    6. Substring() 具体干了些什么?

    在JDK 6中,substring() 提供了一个显示已有字符串char[]的接口,但不创建新字符串。如果需要创建一个新的char[]表示的字符串,可以像下面一样与一个空字符串相加:

    str.substring(m, n) + "";

    这样会创建一个新的字符数组,表示新的字符串。示例方法有时可以使代码运行更快,因为垃圾收集器可以收集未使用的大字符串只保留子串。

    在Oracle JDK 7中 ,substring()会创建一个新的字符数组而不是使用现有的。

    7. String vs StringBuilder vs StringBuffer

    String 与StringBuilder的区别:StringBuilder的是可变的,这意味着可以在创建以后再作修改。
    StringBuilder与StringBuffer的区别: StringBuffer的是同步的,这意味着它是线程安全的,但速度比StringBuilder慢。

    8. 如何重复一个字符串?

    在Java中,我们可以使用Apache公共语言包(Apache Commons Lang package)中的repeat()。

    String str ="abcd";
    String repeated = StringUtils.repeat(str,3); //abcdabcdabcd

    9. 如何转换字符串为日期?

    String str ="Sep 17, 2013";
    Date date = null;
    try {
      date =new SimpleDateFormat("MMMM d, yy", Locale.ENGLISH).parse(str);
    } catch (ParseException e) {
      e.printStackTrace();
    }
    System.out.println(date); // Tue Sep 17 00:00:00 CST 2013

    10. 如何统计某字符在一个字符串中的出现次数?
    使用apache公共语言包中的StringUtils:

    int n = StringUtils.countMatches("11112222","1");
    System.out.println(n);


    发布于 2年前, 阅读(487) | 评论(0) | 投票(0) | 收藏(19) 阅读全文...
  • 212014-04

     Mybatis的前身是iBatis,iBatis原本就是apache的一个开源项目,2010年该项目有apache迁移到了google code,并改名为MyBatis。

    1. 简介
        MyBatis支持普通SQL查询,存储过程和高级映射的优秀持久层框架,消除了几乎所有的JDBC代码和参数的手动设置以及结果集的检索。MyBatis可以使用XML或者注解用于配置和映射,将接口和JavaBean映射成数据库的记录。
        每一个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心。SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来获得,SqlSessionFactoryBuilder对象可以从XML配置文件或从Configuration类获得。例如:

    String resource = "com/alvinliang/mybatis/mybatis-config.xml";
    InputStream is= Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        XML配置文件包含了对MyBatis系统的核心设置,有获取数据库连接实例的数据源和决定事务范围和控制事务管理器。详细内容后面会讲,这里给出一个简单示例:

    <?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>
      <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 resource="com/alvinliang/mybatis/BlogMapper.xml"/>
      </mappers>
    </configuration>

    还有很多可以配置,上面指出了最关键的部分。environment元素体里包含对事务管理和连接池的环境配置。mapppers元素包含了所有mapper映射器,这些mapper的xml文件包含了SQL代码和映射定义信息。

    2. 总体流程
    (1) 加载配置并初始化
      触发条件:加载配置文件,将SQL配置文件加载成一个个MappedStatement对象。
    (2) 接受调用请求
      触发条件:调用MyBatis提供的API
      传入参数:为SQL的ID和传入参数对象
      处理过程:将请求传递给下层的请求的处理层进行处理。
    (3) 处理操作请求
      触发条件:API接口层传递请求过来
      传入参数:为SQL的ID和传入参数对象
      处理过程:
        (A)根据SQL的ID查找对应的MappedStatement对象。
        (B)根据传入参数对象解析MappedStatement对象,得到最终要执行的SQL和执行传入参数。
        (C)获取数据库连接,根据得到的最终SQL语句和执行传入参数到数据库执行,并得到执行结果。
        (D)根据MappedStatement对象中的结果映射配置对得到的执行结果进行转换处理,并得到最终的处理结果。
        (E)释放连接资源。
    (4)返回处理结果将最终的处理结果返回。

    3. 功能框架
      Mybatis可以分为三层:
    (1) API接口层:提供给外部使用的接口API,开发人员可以通过本地API来操纵数据库。
    (2) 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。
    (3) 基础支持层:负责最基本的功能支撑,包括连接管理、事务管理、配置加载和缓存处理等。

    4. 简单使用
    先从SqlSessionFactory对象来获得SqlSession的实例,SqlSession对象包含了对数据库的所有执行SQL操作的方法。例如:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      Blog blog = (Blog) session.selectOne("com.alvinliang.mybatis.BlogMapper.selectBlog", 1);
    } finally {
      session.close();
    }

    下面给出映射的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.alvinliang.mybatis.BlogMapper">
      <select id="selectBlog" resultType="Blog">
        select * from Blog where id = #{id}
      </select>
    </mapper>

    这里只是给出了一个简洁的例子,其中在命名空间“com.alvinliang.mybatis.BlogMapper”中定义了一个名为“selectBlog”的映射语句,这样它允许你使用完全限定名“com.alvinliang.mybatis.BlogMapper.selectBlog”来调用映射语句。
    注意:现在命名空间是必须的,而且命名空间使得接口绑定成为可能,使用命名空间并将它放在合适的Java包空间下,将会使你的代码变得简洁,会在很长的时间内提高MyBatis的作用。

    5. 范围和生命周期
    SqlSessionFactoryBuilder
    这个类可以被实例化,使用和丢弃。一旦你创建了SqlSessionFactory后,这个类就不需要了。因此SqlSessionFactoryBuilder实例的最佳范围就是方法范围(也就是本地方法变量)。你可以重用SqlSessionFactoryBuilder来创建多个SqlSessionFactory实例。

    SqlSessionFactory
    一旦被创建,SqlSessionFactory应该在你的应用执行期间都存在,没有理来处理或者重新创建它。使用SqlSessionFactory的最佳实践是在应用运行期间不要重复创建多次。因此SqlSessionFactory的生命周期是Application范围。很多方法可以做到,如单例模式或者静态单例模式。

    SqlSession
    每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能被共享,也是线程不安全的。因此最佳范围应该是request或者method范围。绝对不能将SqlSession实例的引用放在一个类的静态字段甚至是实例字段中。也绝对不能将SqlSession实例引用放在任何类型的管理范围中,比如Servlet中的HttpSession。如果你正在使用Web框架,可以考虑将SqlSession放在一个和Http Request对象相似的范围内。下面的示例就是一个确保SqlSession关闭的基本模式:

    SqlSession session = sqlSessionFactory.openSession();
    try {
      // do work
    } finally {
      session.close();
    }
    在你的代码中一贯的使用这种模式,将会保证所有的数据库资源都正常的关闭。

    发布于 2年前, 阅读(891) | 评论(0) | 投票(0) | 收藏(10) 阅读全文...
  • 022014-04

    前几天碰到了一个常见的错误,在Jboss下配置了log4j.xml文件,但是配置没有生效。如果你在项目中没有指定使用的log4j的配置文件,最好使用文件名jboss-log4j.xml。该文件在Jboss容器的目录为:${JBOSS_HOME}\server\default\conf下。下面就是基于log4j默认配置的一些基本修改和注释:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
    
        <appender name="FILE" class="org.jboss.logging.appender.DailyRollingFileAppender">
            <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler" />
            <param name="File" value="${jboss.server.log.dir}/server.log" />
            <param name="Append" value="true" />
    
            <!-- Rollover at midnight each day -->
            <param name="DatePattern" value="'.'yyyy-MM-dd" />
    
            <!-- Rollover at the top of each hour
            <param name="DatePattern" value="'.'yyyy-MM-dd-HH"/>
            -->
    
            <layout class="org.apache.log4j.PatternLayout">
                <!-- The default pattern: Date Priority [Category] Message\n -->
                <param name="ConversionPattern" value="%d %-5p [%c] %m%n" />
    
                <!-- The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
                <param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
                -->
            </layout>
        </appender>
        
        <appender name="ErrorFile" class="org.jboss.logging.appender.DailyRollingFileAppender">
            <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler" />
            <param name="File" value="${jboss.server.log.dir}/error.log" />
            <param name="Threshold" value="ERROR" />
            <param name="Append" value="true" />
            <!-- Rollover at midnight each day -->
            <param name="DatePattern" value="'.'yyyy-MM-dd" />
    
            <layout class="org.apache.log4j.PatternLayout">
                <!-- The default pattern: Date Priority [Category] Message\n -->
                <param name="ConversionPattern" value="%d %-5p [%c] %m%n" />
    
                <!-- The full pattern: Date MS Priority [Category] (Thread:NDC) Message\n
                <param name="ConversionPattern" value="%d %-5r %-5p [%c] (%t:%x) %m%n"/>
                -->
            </layout>
        </appender>
    
        <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
            <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler" />
            <param name="Target" value="System.out" />
            <param name="Threshold" value="INFO" />
    
            <layout class="org.apache.log4j.PatternLayout">
                <!-- The default pattern: Date Priority [Category] Message\n -->
                <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" />
            </layout>
        </appender>
    
        <!-- ================ -->
        <!-- Limit categories -->
        <!-- ================ -->
        <category name="org.hibernate">
            <priority value="WARN" />
        </category>
        <category name="org.hibernate.engine.loading.LoadContexts">
            <priority value="ERROR" />
        </category>
        <category name="org.jboss">
            <priority value="INFO" />
        </category>
    
        <!-- Limit the org.apache category to INFO as its DEBUG is verbose -->
        <category name="org.apache">
            <priority value="WARN" />
        </category>
    
        <!-- Limit the jacorb category to WARN as its INFO is verbose -->
        <category name="jacorb">
            <priority value="WARN" />
        </category>
    
        <!-- Limit the org.jgroups category to WARN as its INFO is verbose -->
        <category name="org.jgroups">
            <priority value="WARN" />
        </category>
    
        <!-- Limit the org.quartz category to INFO as its DEBUG is verbose -->
        <category name="org.quartz">
            <priority value="INFO" />
        </category>
    
        <!-- Limit the JSR77 categories -->
        <category name="org.jboss.management">
            <priority value="INFO" />
        </category>
    
        <!-- Limit the org.jboss.serial (jboss-serialization) to INFO as its DEBUG is verbose -->
        <category name="org.jboss.serial">
            <priority value="INFO" />
        </category>
        
        <category name="com.alvinliang">
            <priority value="DEBUG" />
        </category>
    
        <!-- ======================= -->
        <!-- Setup the Root category -->
        <!-- ======================= -->
    
        <root>
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
            <appender-ref ref="ErrorFile" />
        </root>
    
    </log4j:configuration>

    1. Log4j的几种输出方式

    org.apache.log4j.ConsoleAppender(控制台)
    org.apache.log4j.FileAppender(文件)
    org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
    org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定位置)


    2. 日志记录的优先级

    优先级从高到低:OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL。
    log4j建议使用FATAL、ERROR、WARN、INFO、DEBUG。
    你可以在<param name="Threshold" value="ERROR" />来配置level,Threshold是一个全局的过滤器,低于其设置的level将不会显示出来。


    3. 当重启Jboss服务之后是否保存之前的日志

    <param name="Append" value="true" />,设置为true后,当Jboos重启后当前的log不会消失,即在原有日志上增加新日志。


    4. 日志输出格式

        %c     输出所属类的全名,可在修改为 %c{num} ,num表示输出的范围  
                 如:"org.apache.elathen.ClassName",%c{2}将输出elathen.ClassName                
        %d     输出日志时间其格式为 %d{yyyy-MM-dd HH:mm:ss,SSS},可指定格式 如 %d{HH:mm:ss}
        %l      输出日志事件发生位置,包括类目名、发生线程,在代码中的行数
        %n     换行符
        %m    输出代码指定信息,如info("message"),输出message
        %p     输出优先级,即 FATAL ,ERROR 等
        %r     输出从启动到显示该log信息所耗费的毫秒数
        %t     输出产生该日志事件的线程名


    5. 关于category的配置

    category指定了以什么开头的包下的类输出的日志的级别。例如:
    <category name="com.alvinliang">
        <priority value="DEBUG" />
        <appender-ref ref='FILE'/>
    < /category>

    从上面可以看出,项目中以com.alvinliang包开头的所有类中,凡是DEBUG级别的日志可以输出到FILE中。

    这里要注意了,你定义了一个appender-ref=FILE的引用,但是你如果也在root下配置了appender-ref=FILE的引用,会导致输出到FILE的日志会重复。本人碰到过类似的问题。


     

     

    发布于 2年前, 阅读(2377) | 评论(0) | 投票(0) | 收藏(2) 阅读全文...
  • 012014-04

    最近在OSChina上看到很多人都在使用Intellij IDEA,据说是最智能的IDE,于是下载了Intellij IDEA 13来使用看看。刚开始很不习惯,而且感觉界面太丑了,怎么使用怎么不爽,后来尝试来简单配置发现还不错,如下图(图片有点被压缩了,可以单击查看):

     

    如果你已经安装好了Intellij IDEA,接下来跟我一起来配置

    设置界面主题和字体

    File --> Settings --> Appearance,本人设置主题为Intellij,设置字体为微软雅黑,字体大小为12。



    设置快捷键

    File --> Settings --> Keymap --> Eclipse. 这里有很多方案让你选择,如果你已经习惯了使用Eclipse的话,就选择Eclipse吧。

    自动补全代码

    默认是ctrl+space,可以通过Keymap --> Main menu --> code --> Completion来设置。

    去除自动补全大小写敏感

    File --> Settings --> Editor --> Code Completion,设置Case sensitive completion为none。

    显示行号

    File --> Settings --> Editor --> Appearance,勾选show line numbers。

    设置编辑器和控制台的字体

    File --> Settings --> Editor --> Colors & Fonts --> Font / Console Font。去掉勾选Show only monospaced fonts. 之后本人选择了Consolas字体,字号为14。之后你会发现你的Java code漂亮了很多。

    最后

    Intellij IDEA 13使用还是很棒的,至少没有感觉卡顿,还有就是代码补全很nice。如果你感兴趣的话,不妨也试试。

     

    发布于 2年前, 阅读(2894) | 评论(0) | 投票(0) | 收藏(1) 阅读全文...
  • 092014-03

    最近想体验一下Ubuntu系统,之后在虚拟机上安装Ubuntu 13.10,安装虚拟机步骤可以参考:http://my.oschina.net/liangbo/blog/206541

    下面是在虚拟机上安装过程:

    1. 在VMware的菜单栏中点击“文件”-->“新建虚拟机”,如下图:



    2. 在“新建虚拟机向导”界面选择“自定义(高级)”,默认下一步:



    选择,稍后安装操作系统:


    依次选择Linux 和 Ubuntu 64位:


    定义你自己想要的虚拟机名称,如:Ubuntu 13.10。并且选择自己新建好的位置:




    我这里默认使用了1G的内存给虚拟机:


    我这里选择的是“使用桥接网络”,因为我使用的笔记本,并且使用的无线网。如果你是直插网线的话,可以选择“使用网络地址转换(NAT)”。


    一直点“下一步”:




    下面选择“创建新虚拟磁盘”:


    这里我使用的是默认的20G,并且选择“将虚拟磁盘存储为单个文件”:


    这里是将你创建好的20G的磁盘文件放置的路径,尽量不要使用默认的配置,选择一个非系统盘的路径,根据自己的喜好定义文件路径:


    下面就是你新建虚拟机的配置预览了,看下图,如果你使用了默认的配置,文件的路径将会在C:\Users\...\Documents文件下,占用你大量的系统磁盘空间。


    3. 这样你就完成了虚拟机的配置了,但是你还不能启动你的虚拟机,第一次启动需要配置系统iso的路径:



    点击“编辑虚拟机设置”后,弹出如下配置:



    4. 好的,现在启动你的虚拟机。
    第一次启动,会自动安装你配置的iso文件,很简单,直接一直点继续就行,根据你电脑的配置安装速度快慢也不一样,等它安装成功就行。在选择语言的时候,注意选择“中文”吧。

    1)登录界面如下:



    2)登录后界面如下:



    现在可以体验Ubuntu了。启动该系统的时候,主系统最好闲置,占用最小的系统资源,不然虚拟机中的Ubuntu会有点卡。

    发布于 2年前, 阅读(4013) | 评论(0) | 投票(0) | 收藏(2) 阅读全文...
  • 092014-03

    如果你不想安装多操作系统,又想体验新系统,可以安装虚拟机VMware。

    1. 先到官网下载最新的虚拟机VMware:http://www.vmware.com/go/tryworkstation-win-cn



    2. 下载完成之后,直接按照步骤安装到要输入密钥:



    3. 下载一个注册机:http://pan.baidu.com/s/1pJucVXL
    输入密钥后,安装成功,启动VMware。

    发布于 2年前, 阅读(352) | 评论(0) | 投票(0) | 收藏(0) 阅读全文...
  • 052014-03
    Android应用的开发的一项内容就是用户界面开发了。Android 提供了大量功能丰富的UI组件。Android的界面是由布局和组件协同完成的。

     
     Android所有UI组件都继承了View类,View类有一个重要的子类:ViewGroup,但ViewGroup通常作为其他组件的容器使用。现在介绍以ViewGroup为基类派生出来的布局管理器。

     Android的布局方式有以下几种:线性布局(Linear Layout)、表格布局(Table Layout)、帧布局(Frame Layout)、相对布局(Relative Layout)、网格布局(Grid Layout)、绝对布局(Absolute Layout)

    1. 线性布局(Linear Layout)
        这种布局比较常用,也比较简单,就是每个元素占一行,当然也可能声明为横向排放,也就是每个元素占一列。Android的线性布局不会换行,当组件一个挨着一个排列到头之后,剩下的组件将不会被显示出来。LinearLayout可以控制各组件横向排列,也可控制组件纵向排列。(通过设置android:orientation属性控制),例如定义如下XML布局管理器,res/layout/main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical" >
    
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button1" />
    
        <Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button2" />
    
        <Button
            android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button3" />
    
        <Button
            android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button4" />
    
        <Button
            android:id="@+id/button5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button5" />
    </LinearLayout>

    根据上面LinearLayout的配置,以线性的方式,垂直居中放置组件,运行效果如下:



    2. 表格布局(Table Layout)
        1)TableLayou继承了LinearLayout,因此它的本质依然是线性布局管理器。表格布局采用行、列的形式管理UI组件,TableLayout并不需要明确的声明多少行、列,而是通过添加TableRaw、其他组件来控制表格的行数和列数。
       
        2)每次向TableLayout添加一个TableRaw,该TableRaw就是一个表格行,同时TableRaw也是一个容器,它可以不断的添加其他组件,每个组件占用一列。
        
        3)如果直接向TableLayout中添加组件,那么这个组件将直接占用一行。

       4)表格布局的三种单元格设置:
            a)Shrinkable:表示该列所有单元格的宽度可以被收缩。
            b)Stretchable:表示该列所有单元格的宽度可以被拉伸。
            c)Collapsed:表示该列所有单元格会被隐藏。
        
        下面来看下程序示范,TableLayoutTest/res/layout/main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:shrinkColumns="1"
        android:stretchColumns="2"
        android:collapseColumns="3">
        <!-- 定义第一个表格布局,指定第2列收缩,第3列拉伸 ,第4列隐藏-->
        
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/bn1" />
    
        <TableRow>
            <Button
                android:id="@+id/button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/bn2" />
    
            <Button
                android:id="@+id/button3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/bn3" />
    
            <Button
                android:id="@+id/button4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/bn4" />
            
            <Button
                android:id="@+id/button5"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/bn5" />
        </TableRow>
    
    </TableLayout>
    上面的TableLayout配置中,第一个button独自占用一行,第二列收缩,第三列拉伸,第四列隐藏了。运行效果如下:



    3. 帧布局(FrameLayout)
        FrameLayout直接继承自ViewGroup组件。帧布局容器为每个加入其中的组件创建一个空白的区域,每个子组件占据一帧,这些帧都会根据gravity属性执行自动对齐。

        下面来看下程序示范,FrameLayoutTest/res/layout/main.xml:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        
        <TextView android:id="@+id/view01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" 
            android:width="320px"
            android:height="320px"
            android:background="#f00" />
        
        <TextView android:id="@+id/view02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" 
            android:width="280px"
            android:height="280px"
            android:background="#0f0" />
    
        <TextView android:id="@+id/view03"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" 
            android:width="240px"
            android:height="240px"
            android:background="#00f" />
        
        <TextView android:id="@+id/view01"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" 
            android:width="200px"
            android:height="200px"
            android:background="#ff0" />    
        
        <TextView android:id="@+id/view4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" 
            android:width="160px"
            android:height="160px"
            android:background="#f0f" />    
        
         <TextView android:id="@+id/view05"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" 
            android:width="120px"
            android:height="120px"
            android:background="#0ff" />   
    
    </FrameLayout>

    上面的FrameLayout定义了6个TextView,先定义的TextView位于底部,后定义的TextView位于上层,上层的组件会覆盖下层的组件,但是由于底部的组件大,不能完全覆盖,因此运行效果如下:


    4. 相对布局(Relative Layout)
        RelativeLayout内的子组件总是相对兄弟组件、父组件来决定的。下面来看下RelativeLayout.LayoutParams属性:
        1)
     只能设置为boolean值得属性:
             Android:layout_centerHorizontal         位于布局容器的水平居中
             Android:layout_centerVertical             位于布局容器的垂直居中
             Android:layout_centerInParent            位于布局容器的中央位置
             Android:layout_alignParentBottom      与布局容器底部对齐
             Android:layout_alignParentLeft           与布局容器左边对齐
             Android:layout_alignParentRight         与布局容器右边对齐
             Android:layout_alignParentTop           与布局容器顶端对齐

        2)
     只能设置为其他UI组件ID的属性:
             Android:layout_toRightOf                      位于给出ID组件的右侧
             Android:layout_toLeftOf                        位于给出ID组件的左侧
             Android:layout_about                            位于给出ID组件的上方
             Android:layout_below                            位于给出ID组件的下方
             Android:layout_alignTop                        位于给出ID组件的上边界对齐
             Android:layout_alignBottom                   位于给出ID组件的下边界对齐
             Android:layout_alignLeft                        位于给出ID组件的左边界对齐
             Android:layout_alignRight                      位于给出ID组件的右边界对齐

      下面来看下程序示范,RelativeLayoutTest/res/layout/main.xml:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <Button android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button1" 
            android:layout_centerInParent="true" />
    
        <Button android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button2" 
            android:layout_above="@id/button1"
            android:layout_alignLeft="@id/button1" />
        
        <Button android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button3" 
            android:layout_below="@id/button1"
            android:layout_alignLeft="@id/button1" />
        
        <Button android:id="@+id/button4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button4" 
            android:layout_toLeftOf="@id/button1"
            android:layout_alignTop="@id/button1" />
        
        <Button android:id="@+id/button5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/button5" 
            android:layout_toRightOf="@id/button1"
            android:layout_alignTop="@id/button1" />
    
    </RelativeLayout>

    运行效果如下: 



    5. 网格布局(Grid Layout)

        GridLayout是Android 4.0新增的布局管理器,GridLayout的作用类似于HTML中的table标签,它把整个容器划分成 Rows x Columns 个网格,每个网格放置一个组件。也可以设置一个组件跨越多少列或行。

        常用的XML属性有:
        android:layout_column                设置该子组件在GridLayout的第几列
        android:layout_columnSpan         设置该子组件在GridLayout横向上跨几列
        android:layout_gravity                 设置以何种方式占据网格空间
        android:layout_raw                      设置该子组件在GridLayout的第几行
        android:layout_rawSpan               设置该子组件在GridLayout纵向上跨几行

      下面来看下程序示范,GridLayoutTest/res/layout/main.xml:

    <GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:rowCount="6"
        android:columnCount="4"
        android:id="@+id/root" >
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_columnSpan="4"
            android:textSize="50sp"
            android:layout_marginLeft="4px"
            android:layout_marginRight="4px"
            android:padding="5px"
            android:layout_gravity="right"
            android:background="#eee"
            android:textColor="#000"
            android:text="0"/>
        
        <Button 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_columnSpan="4"
            android:text="Clear"/>
    </GridLayout>

    注意了在创建该项目的时候,最低的API至少为14,即Android 4.0。不然GridLayout属性会报错。 

    GridLayoutTest/src/com/lvinliang/gridlayout/MainActivity:
    public class MainActivity extends Activity {
        
        GridLayout gridLayout;
        
        String[] chars = new String[] {
                "7", "8", "9", "÷",
                "4", "5", "6", "x",
                "1", "2", "3", "-",
                ".", "0", "=", "+"
        };
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            gridLayout = (GridLayout) findViewById(R.id.root);
            for (int i = 0; i < chars.length; i++ ) {
                Button bn = new Button(this);
                bn.setText(chars[i]);
                bn.setTextSize(40);
                // 指定组件所在的行
                GridLayout.Spec rowSpec = GridLayout.spec(i / 4 + 2);
                // 指定组件所在的列
                GridLayout.Spec columnSpec = GridLayout.spec(i % 4);
                GridLayout.LayoutParams params = new GridLayout.LayoutParams(rowSpec, columnSpec);
                params.setGravity(Gravity.FILL);
                gridLayout.addView(bn, params);
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    }

    由上面GridLayout定义一个计算机界面,界面设计成一个6 x 4的网格,显示效果如下: 


    6. 绝对布局(Absolute Layout)
        Android将不提供任何布局控制,而是由开发人员自己通过X坐标、Y坐标来控制组件的位置。
        如下所示布局文件:

    <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:id="@+id/AbsoluteLayout01" 
       android:layout_width="fill_parent" 
       android:layout_height="fill_parent" 
       >
       <TextView android:id="@+id/text01"
         android:text="绝对布局"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:layout_x="100dip"
         android:layout_y="100dip">
       </TextView>
    </AbsoluteLayout>

    不推荐使用绝对布局,因为运行Android应用的手机不同,屏幕大小、分辨率都存在很大的差异,使用绝对布局很难兼顾屏幕大小和分辨率问题。

    最后,来看下Android一些常用的距离单位:

    px: 像素,每个px对应屏幕上的一个点
    dipdp:一种基于屏幕密度的抽象单位。在每英寸160点的显示器上,1dip = 1px。公式:px = dip * (dpi / 160)
    sp:处理字体的大小。
    in: 英寸,标准长度单位。
    pt: 磅,1/72英寸。


    发布于 2年前, 阅读(650) | 评论(0) | 投票(0) | 收藏(53) 阅读全文...
  • 272014-02

    1. 在搭建Android开发环境之前,你需要准备如下几个文件:
        
        其中android-sdks可以到官网(http://developer.android.com/index.html)下载。

    2. 安装JDK运行环境

        这个是Java环境所必须的,也很简单,你可以参考我写的安装Java环境的blog,地址:http://my.oschina.net/liangbo/blog/89615 。

    3. 安装Android SDK

        先从官网下载解压包,然后解压到你想要的任何位置,解压后如下图:

        

        双击SDK Manager.exe,运行后如下:

        

        按照上图,勾选你需要的选项,你也可以全选,点击“Install 8 packages”就可以了。有些人不知道“Extras”勾选哪些选项,你需要选择的有:
        Android Support Library、Google USB Driver、Google Web Driver、Intel x86 Emulator Accelerator选项即可。
        
        如果你下载报错,你可以参考这篇blog, 地址如下: http://my.oschina.net/liangbo/blog/193385 。

    4. Android Path的配置

        在环境变量path中添加android sdk的绝对路径。

        

        之后,进入cmd窗口,输入android -h, 如果出现如下图所类似的输出,表示你已经成功安装了Android SDK了。
       
        

    5. 在Eclipse中安装Android插件(ADT)

        先到Eclipse官网(http://www.eclipse.org/downloads/)下载最新版的Eclipse Kepler,运行Eclipse,在菜单栏选择Help-->Install New Software。
        在弹出的对话框中,输入:http://dl-ssl.google.com/android/eclipse或https://dl-ssl.google.com/android/eclipse 。

        

        如果你无法通过这种方式获得Android插件的话,你可以手动到Android官网去下载ADT插件,地址:http://developer.android.com/sdk/eclipse-adt.html 。
        下载完后,你可以点击‘Add’button,在弹出的对话框中输入如下信息,确定即可。
        
        

        安装后,重启Eclipse,重启后Eclipse会自动弹出指定Android SDK路径的配置,选择 Use existing SDKs ,Existing Location中选择你解压的SDK的路径。
        如果看到有两个Android图标,现在你已经基本完成了Android开发环境的配置了。
       
        

        如果没有的,你可以到菜单栏 Windows --> Customer Perspective --> Commond Groups Availability进行配置。

        

    6. Eclipse开发Android项目

        先配置好一个模拟器,点击刚才看到的那个android手机小图标,'New'一个模拟器,然后单击start。

        

        运行成功后,我们可以看到如下:
       
        

        使用Eclipse开发的一个数独软件,在eclipse运行后,在模拟器中打开效果如下:

        

        今天Android开发环境的配置到此结束!

    发布于 2年前, 阅读(157) | 评论(0) | 投票(0) | 收藏(13) 阅读全文...
  • 242014-01

    私服不是Maven的核心概念,它仅仅是一种衍生出来的特殊的Maven仓库。通过建立自己的私服,就可以降低中央仓库负荷、节省外网带宽、加速Maven构建、自己部署构建等,从而高效地使用Maven。Nexus也是当前最流行的Maven仓库管理软件。

    1. 安装Nexus
    Nexus是典型的Java Web应用,它有两种安装包,一种是包含Jetty容器的Bundle包,另一种是不包含Web容器的war包。

    1)下载Nexus
    读者可以从官网http://www.sonatype.org/nexus/ 下载最新的Nexus,也可以到我分享的路径下载http://download.csdn.net/detail/amuguelove/6578111(竟然还要一个积分,服了自己了,没积分的就忽略这个地址吧)。

    2)Bundle方式安装Nexus
    a. 首先看下解压后的目录,结构:
        
    nexus-2.6.2-01: 该目录包含了Nexus运行所需要的文件,如启动脚本、依赖jar包等。
    sonatype-work:该目录包含Nenus生成的配置文件、日志文件、仓库文件等。
    其中第一个目录是运行Nexus必须的,而第二个不是必须的,Nexus会在运行的时候动态创建该目录。

    b. 配置Path,启动Nexus
    首先在环境变量path下加入如下地址:D:\j2ee\nexus-2.6.2-01-bundle\nexus-2.6.2-01\bin;之后在cmd下启动Nexus服务:

    如果看到以上输出,就说明启动成功了。这时打开浏览器访问:http://localhost:8081/nexus 就可以看到Nexus的界面了,如下图:

    这时你可以单击界面右上角的Login进行登录,Nexus默认管理用户名和密码为admin/admin123。

    2. Nexus的索引
    这时你使用Nexus搜索插件得不到任何结果,为了能够搜索Maven中央库,首先需要设置Nexus中的Maven Central仓库下载远程索引。如下图:

    单击左边导航栏的Repositories,可以link到这个页面,选择Central,点击Configuration,里面有一个Download Remote Indexes配置,默认状态是false,将其改为true,‘Save’后,单击Administration==> Scheduled Tasks, 就有一条更新Index的任务,这个是Nexus在后天运行了一个任务来下载中央仓库的索引。由于中央仓库的内容比较多,因此其索引文件比较大,Nexus下载该文件也需要比较长的时间。请读者耐心等待把。如果网速不好的话,可以使用其他人搭建好的的Nexus私服。后面会介绍。下图为Nexus后台运行的task图:

    3. 配置Maven从Nexus下载构件

    1)在POM中配置Nexus私服,这样的配置只对当前的Maven项目有效。

    <repositories>
          <repository>
              <id>nexus</id>
              <name>Nexus Repository</name>
              <url>http://localhost:8081/nexus/content/groups/public/</url>
              <releases>
                  <enabled>true</enabled>
              </releases>
              <snapshots>
                  <enabled>true</enabled>
              </snapshots>
          </repository>
      </repositories>

    2)在settings.xml中配置profile元素,这样就能让本机所有的Maven项目都使用自己的Maven私服。
    <mirrors>
        <mirror>
          <id>central</id>
          <mirrorOf>*</mirrorOf>
          <name>Human Readable Name for this Mirror.</name>
          <url>http://localhost:8081/nexus/content/groups/public/</url>
        </mirror>
      </mirrors>
      <profiles>
        <profile>
          <id>nexus</id>
          <repositories>
            <repository>
              <id>nexus</id>
              <name>Nexus</name>
              <url>http://localhost:8081/nexus/content/groups/public/</url>
                <releases>
    			<enabled>true</enabled>
    		  </releases>
              <snapshots>
    			<enabled>true</enabled>
    		  </snapshots>
            </repository>
          </repositories>
        </profile>
    </profiles>

    以上配置所有Maven下载请求都仅仅通过Nexus,以全面发挥私服的作用。

    4. 部署构件到Nexus

    1)在POM中配置

    <project>
      ...  
      <distributionManagement>
    
        <snapshotRepository>
            <id>user-snapshots</id>
            <name>User Project SNAPSHOTS</name>
            <url>http://localhost:8081/nexus/content/repositories/MyUserReposSnapshots/</url>
        </snapshotRepository>
        
          <repository>
              <id>user-releases</id>
              <name>User Project Release</name>
              <url>http://localhost:8081/nexus/content/repositories/MyUserReposRelease/</url>
          </repository>
          
      </distributionManagement>
       ...
    </project>
    2)settings.xml中配置认证信息,Nexus的仓库对于匿名用户是只读的。
    <servers>
      
        <server>
          <id>user-snapshots</id>
          <username>lb</username>
          <password>123456</password>
        </server>
    	
        <server>
          <id>user-releases</id>
          <username>lb</username>
          <password>123456</password>
        </server>
    	
      </servers>


    最后,如果不想自己构建Nexus私服,或者更新Index很慢的话,可以使用OSChina搭建的Nexus私服,地址如下:http://maven.oschina.net/index.html,如下图:

    建议大家可以在浏览器中收藏这个网站,平时也可以用来查看一下一些构件的依赖,如上图的右下角显示的。


    发布于 2年前, 阅读(7752) | 评论(2) | 投票(2) | 收藏(64) 阅读全文...
  • 232014-01

        我们使用Maven应用到实际项目的时候,需要将项目分成不同的模块。这个时候,Maven的聚合特性能够把项目的各个模块聚合在一起构件,而Maven的继承特性则能帮助抽取各模块相同的依赖和插件等配置。在简化POM的同时,还能促进各个模块配置的一致性。下面以具体项目来讲解:

    1. 项目结构


    以上有五个项目分别为user-parent, user-core, user-log, user-dao, user-service. 其中user-parent项目为其他项目的父项目,只是帮助其他模块构建的工具,它本身并无实质的内容,只有一个pom.xml文件。

    2. user-parent的pom.xml详情如下(下文简称为父POM)

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.liangbo.user</groupId>
      <artifactId>user-parent</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>pom</packaging>
    
      <modules>
          <module>../user-core</module>
          <module>../user-dao</module>
          <module>../user-log</module>
          <module>../user-service</module>
      </modules>
      
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.version>4.10</junit.version>
        <mysql.driver>com.mysql.jdbc.Driver</mysql.driver>
        <mysql.url>jdbc:mysql://localhost:3306/mysql</mysql.url>
        <mysql.username>root</mysql.username>
        <mysql.password>password</mysql.password>
      </properties>
      
      <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            
            <dependency>
                <groupId>com.liangbo.user</groupId>
                <artifactId>user-core</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
            
            <dependency>
                <groupId>com.liangbo.user</groupId>
                <artifactId>user-log</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
            
            <dependency>
                <groupId>com.liangbo.user</groupId>
                <artifactId>user-dao</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
            
            <dependency>
                <groupId>com.liangbo.user</groupId>
                <artifactId>user-log</artifactId>
                <version>0.0.1-SNAPSHOT</version>
                <exclusions>
                    <exclusion>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.9</version>
            </dependency>
        
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.1.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <version>3.6.10.Final</version>
            </dependency>
    
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.16</version>
            </dependency>
        
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.26</version>
            </dependency>
    
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.7.5</version>
            </dependency>
    
            <dependency>
                <groupId>javassist</groupId>
                <artifactId>javassist</artifactId>
                <version>3.12.1.GA</version>
            </dependency>
            
        </dependencies>
      </dependencyManagement>
      
      <build>
          <pluginManagement>
              <plugins>
                  <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-source-plugin</artifactId>
                    <version>2.2.1</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals><goal>jar-no-fork</goal></goals>
                        </execution>
                    </executions>
                </plugin>
                
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>sql-maven-plugin</artifactId>
                    <version>1.5</version>
                    <dependencies>
                        <dependency>
                            <groupId>mysql</groupId>
                            <artifactId>mysql-connector-java</artifactId>
                            <version>5.1.26</version>
                        </dependency>
                    </dependencies>
                    <configuration>
                        <driver>${mysql.driver}</driver>
                        <url>${mysql.url}</url>
                        <username>${mysql.username}</username>
                        <password>${mysql.password}</password>
                        <sqlCommand>
                            create database IF NOT EXISTS maven_test
                        </sqlCommand>
                    </configuration>                
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>execute</goal>
                            </goals>
                        </execution>                
                    </executions>
                </plugin>
                
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-rar-plugin</artifactId>
                    <version>2.3</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals><goal>rar</goal></goals>
                        </execution>
                    </executions>
                </plugin>
              </plugins>
          </pluginManagement>
      </build>
    </project>

    上面的pom.xml文件既有Maven的聚合特性又有继承特性。这样做是为了更加方便管理其他模块。其中元素modules,是实现聚合的最核心配置。多个子模块之间的pom有很多的相同的配置,这时候可以全部提取出来放到父项目中。重复往往就意味着更多的劳动和更多的潜在的问题。那么子模块如何来继承他的父项目呢?

    3. 下面来看下user-core项目pom.xml的配置

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <parent>
          <groupId>com.liangbo.user</groupId>
          <artifactId>user-parent</artifactId>
          <version>0.0.1-SNAPSHOT</version>
          <relativePath>../user-parent/pom.xml</relativePath>
      </parent> 
    
      <artifactId>user-core</artifactId>
      <packaging>jar</packaging>
    
      <name>user-core</name>
      <url>http://maven.apache.org</url>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>
    
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>
    
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
    
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
        </dependency>
      </dependencies>
      
      <build>
          <plugins>
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
              </plugin>
              
              <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                <artifactId>sql-maven-plugin</artifactId>
              </plugin>
              
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-rar-plugin</artifactId>
              </plugin>
          </plugins>
      </build>
    </project>

    其中设置好relativePath非常重要,不然无法找到父POM。这时候子POM中只需要配置groupId和artifactId就可以了。

    4. 依赖管理和插件管理

    上述子POM配置简单了很多,是因为父POM引用了依赖管理和插件管理的概念。
    如果父POM没有配置依赖管理和插件管理的话,继承它的子模块会将父所有的依赖和插件都继承下来,显然这是不可行的。接下来讲下如何配置的:

    Maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性。在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它可以约束dependencies下的依赖使用。插件管理同上,需要在父POM中加入pluginManagement元素。

    最后,说下聚合与继承的关系,多模块Maven中的聚合与继承其实是两个不同的概念,其目的是不同的。前者主要是为了方便快速构建项目,后者主要是为了消除重复配置




    发布于 2年前, 阅读(679) | 评论(0) | 投票(0) | 收藏(6) 阅读全文...
  • 202014-01

    前面我们已经讲过坐标、依赖以及仓库,Maven的另外两个核心概念是生命周期和插件。生命周期和插件二者协同工作,密不可分。

    1. Maven生命周期基本概念

    1) Maven的生命周期就是为了对所有的构建过程进行抽象和统一。Maven总结了一套高度完善的、易扩展的生命周期,包括了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。

    2) Maven的生命周期是抽象的,生命周期本身不做任何实际的工作,在Maven的设计中,实际的任务都交给插件来完成。其实这种思想和设计模式中的模版方法(Template Method)很相似。

    2. 生命周期详解

    1)三套生命周期

    Maven有三套相互独立的生命周期,分别为clean、default和site。clean生命周期的目的是清理项目,default生命周期的目的是构建项目,而site生命周期的目的是建立项目站点。

    2)clean生命周期

    clean生命周期的目的是清理项目,它包括如下三个阶段:

    a)pre-clean:执行一些清理前需要完成的工作。

    b)clean:清理上一次构建的文件。

    c)post-clean:执行一些清理后需要完成的工作。

    3) default生命周期

    default生命周期定义了真正构建时所需要执行的所有步骤,它是所有生命周期中最核心的部分。

    a)validate

    b)initialize

    c)generate-sources

    d)process-sources

    e)generate-resources

    f) process-resources

    g)compile:编译项目的主源码,即编译src/main/java目录下的Java文件至项目输出的主classpath中。

    h)process-classes

    i)generate-test-sources

    j)process-test-sources

    k)generate-test-resources

    l)process-test-resources

    m)test-compile:编译项目的测试代码,即编译src/test/java目录下的Java文件至项目输出的测试classpath目录中。

    n)process-test-classes

    o)test:使用单元测试框架运行测试。

    p)prepare-package

    q)package:接受编译好的代码,打包成可发布的格式。如:.jar

    r)pre-integration-test

    s)integration-test

    t)post-integration-test

    u)verify

    v)install:将包安装到Maven本地仓库,供本地其他Maven项目使用。

    w)deploy:将最终的包复制到远程仓库,供其他开发人员和Maven项目使用。

    4) site生命周期

    site生命周期的目的是建立和发布项目站点。

    a)pre-site:执行一些在生成项目站点之前需要完成的工作。

    b)site:生成项目站点文档。

    c)post-site:执行一些在生成项目站点之后需要完成的工作。

    d)site-deploy:将生成的项目站点发布到服务器上。

    5)Window下的命令行执行Maven任务

    主要是调用Maven的生命周期的阶段,以下几个常用的命令:

    mvn clean、mvn test、mvn clean install、mvn clean deploy site-deploy。

    3. 插件详解

    1)插件目标

    我们已经知道,Maven的核心仅仅定义了抽象的生命周期,具体的任务是交给插件完成的,插件以独立的构件形式存在的。对于插件本身,为了能够复用代码,它往往能够完成多个任务。每个任务就是一个插件目标。

    2) 插件绑定

    Maven的生命周期与插件是相互绑定的,用以完成实际的构建任务。具体而言,是生命周期的阶段和插件的目标相互绑定,以完成一项具体的任务。如:项目编译这一任务,它对应了default生命周期中的compile这一阶段,而maven-compiler-plugin这一插件的compile目标能够完成该任务。

    3)内置绑定

    Maven为一些主要的生命周期阶段绑定了很多插件目标。比如:clean生命周期中的clean阶段,与maven-clean-plugin:clean绑定。

    下面我对hello-world项目执行mvn clean install命令,(本人直接使用eclipse执行,命令为clean install),看下面执行了哪些插件目标:

    [INFO] Scanning for projects...
    [INFO]                                                                         
    [INFO] ------------------------------------------------------------------------
    [INFO] Building hello-world 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello-world ---
    [INFO] Deleting D:\code\maven\hello-world\target
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\main\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ hello-world ---
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:\code\maven\hello-world\target\classes
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\test\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ hello-world ---
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:\code\maven\hello-world\target\test-classes
    [INFO] 
    [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-world ---
    [INFO] Surefire report directory: D:\code\maven\hello-world\target\surefire-reports
    
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running com.alvinliang.maven.HelloWorldTest
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.067 sec
    
    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] 
    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-world ---
    [INFO] Building jar: D:\code\maven\hello-world\target\hello-world-0.0.1-SNAPSHOT.jar
    [INFO] 
    [INFO] --- maven-install-plugin:2.4:install (default-install) @ hello-world ---
    [INFO] Installing D:\code\maven\hello-world\target\hello-world-0.0.1-SNAPSHOT.jar to D:\library\maven\repository\com\alvinliang\maven\hello-world\0.0.1-SNAPSHOT\hello-world-0.0.1-SNAPSHOT.jar
    [INFO] Installing D:\code\maven\hello-world\pom.xml to D:\library\maven\repository\com\alvinliang\maven\hello-world\0.0.1-SNAPSHOT\hello-world-0.0.1-SNAPSHOT.pom
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 5.715s
    [INFO] Finished at: Mon Jan 20 22:28:09 CST 2014
    [INFO] Final Memory: 16M/167M
    [INFO] ------------------------------------------------------------------------

    4)自定义绑定

    除了内置绑定外,用户可以自己选择将某个插件目标绑定到生命周期的某个阶段上。例如:创建项目的源码,没有对应的内置绑定,这时候就需要用户自己自定义绑定。

    4. 插件的配置

    1)命令行插件配置

    用户可以在Maven命令中使用-D参数,并伴随一个参数键=参数值的形式,来配置插件的参数。

    如:mvn install -Dmaven.test.skip = true

    2)Eclipse中执行 install -Dmaven.test.skip = true,结果如下:

    [INFO] Scanning for projects...
    [INFO]                                                                         
    [INFO] ------------------------------------------------------------------------
    [INFO] Building hello-world 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\main\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ hello-world ---
    [INFO] Nothing to compile - all classes are up to date
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-world ---
    [INFO] Not copying test resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ hello-world ---
    [INFO] Not compiling test sources
    [INFO] 
    [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-world ---
    [INFO] Tests are skipped.
    [INFO] 
    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-world ---
    [INFO] 
    [INFO] --- maven-install-plugin:2.4:install (default-install) @ hello-world ---
    [INFO] Installing D:\code\maven\hello-world\target\hello-world-0.0.1-SNAPSHOT.jar to D:\library\maven\repository\com\alvinliang\maven\hello-world\0.0.1-SNAPSHOT\hello-world-0.0.1-SNAPSHOT.jar
    [INFO] Installing D:\code\maven\hello-world\pom.xml to D:\library\maven\repository\com\alvinliang\maven\hello-world\0.0.1-SNAPSHOT\hello-world-0.0.1-SNAPSHOT.pom
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 2.481s
    [INFO] Finished at: Mon Jan 20 22:35:59 CST 2014
    [INFO] Final Memory: 13M/100M
    [INFO] ------------------------------------------------------------------------

    5. 使用maven-help-plugin描述插件

    在cmd中执行mvn help:describe -Dplugin=compiler,结果如下:

    [INFO] --- maven-help-plugin:2.2:describe (default-cli) @ standalone-pom ---
    [INFO] org.apache.maven.plugins:maven-compiler-plugin:3.1
    
    Name: Maven Compiler Plugin
    Description: The Compiler Plugin is used to compile the sources of your
      project.
    Group Id: org.apache.maven.plugins
    Artifact Id: maven-compiler-plugin
    Version: 3.1
    Goal Prefix: compiler
    
    This plugin has 3 goals:
    
    compiler:compile
      Description: Compiles application sources
    
    compiler:help
      Description: Display help information on maven-compiler-plugin.
        Call mvn compiler:help -Ddetail=true -Dgoal=<goal-name> to display
        parameter details.
    
    compiler:testCompile
      Description: Compiles application test sources.
    
    For more information, run 'mvn help:describe [...] -Ddetail'


    发布于 2年前, 阅读(673) | 评论(0) | 投票(0) | 收藏(2) 阅读全文...
  • 152014-01

    Android SDK Manager更新不了,出现错误提示:"Failed to fetch URL..."!

    可以用以下办法解决:

    使用SDK Manager更新时出现问题 Failed to fetch URL https://dl-ssl.google.com/android/repository/repository-6.xml, reason: Connection to https://dl-ssl.google.com refused Failed to fetch URL http://dl-ssl.google.com/android/repository/addons_list-1.xml, reason: Connection to http://dl-ssl.google.com refused Failed to fetch URL https://dl-ssl.google.com/android/repository/addons_list-1.xml, reason: hostname in certificate didn't match: <dl-ssl.google.com> != <www.google.com> 更新ADT时无法解析https://dl-ssl.google.com/android/eclipse

    由于某些众所周知又无法理解的原因,我们大陆使用Google的服务会出现种种问题,譬如Android开发也会出现阻碍。一种方法是使用http协议而不是https协议,因为https协议进行了加密处理,大陆因为无法审查,直接封死,而http协议则进行过滤处理,如果不访问乱七八糟的东西,更新个SDK还是没问题的。

    解决方法如下:

    1. ADT更新

    更新ADT插件的时候则使用网址http://dl-ssl.google.com/android/eclipse,而不是https://dl-ssl.google.com/android/eclipse,这个在官方开发文档里也有介绍。 但是昨天的情况就是使用http协议也无法访问。对于ADT还是建议手动下载。

    2. SDK更新 
    1) 在SDK Manager下Tools->Options打开了SDK Manager的Settings,选中“Force https://… sources to be fetched using http://…”,强制使用http协议。             
    2) 然后改hosts文件。Windows在C:\WINDOWS\system32\drivers\etc\hosts目录下,Linux用户打开/etc/hosts文件。打开文件后添加以下内容。
    203.208.46.146    www.google.com 
    74.125.113.121    developer.android.com 
    203.208.46.146    dl.google.com 
    203.208.46.146    dl-ssl.google.com
    注意:在windows上无法修改hosts文件,你可以先拷贝到桌面,修改好了以后,在覆盖系统文件,就可以了



    发布于 2年前, 阅读(4455) | 评论(1) | 投票(2) | 收藏(8) 阅读全文...
  • 282013-11

    在了解Maven如何使用仓库后,我们将能更高效的使用Maven。

    前面我们已经讲过Maven的坐标机制,任何Maven项目使用任何构件的方式都是完全相同的。在此基础上,Maven可以在某个位置统一存储所有Maven项目共享的构件,这个统一的位置就是仓库。实际的Maven项目将不再各自存储其依赖文件,它们只需要声明这些依赖的坐标,在需要的时候,Maven会自动根据坐标找到仓库中的构件,并使用它们。

    1. Maven仓库布局

    Maven是如何根据坐标来定位路径的呢?下面举一个实际的例子:
    有这样一个构件:groupId=org.testng、artifactId=testng、version=5.8、classifier=jdk15、packaging=jar,其对应的路径生成步骤如下:

    1)基于groupId,将org.testng转换成org/testng/。
    2)基于artifactId,路径变成org/testng/testng/。
    3)使用版本信息,得到路径为org/testng/testng/5.8/。
    4)依次加上artifactId,分隔符连字号,以及version,于是构件路径变成了org/testng/testng/5.8/testng-5.8。
    5)如果有classifier信息,路径就变成org/testng/testng/5.8/testng-5.8-jdk5。
    最后由packaging决定构件的扩展名,所以最后的路径为org/testng/testng/5.8/testng-5.8-jdk5.jar。

    2. Maven仓库的分类

    仓库分类:本地仓库和远程仓库。Maven根据坐标寻找构件的时候,它先会查看本地仓库,如果本地仓库存在构件,则直接使用;如果没有,则从远程仓库查找,找到后,下载到本地。

    1)本地仓库
    默认情况下,每个用户在自己的用户目录下都有一个路径名为.m2/repository/的仓库目录。我们也可以自定义本地仓库的地址,如下:

    这样,用户的本地仓库被设置成了D:/library/maven/repository/。我们需要从Maven安装目录复制$MAVEN_HOME/conf/settings.xml文件复制到D:/library/maven下进行编辑。大家不要直接修改全局目录下的settings.xml。

    我们可以将依赖从远程仓库下载到本地仓库,也可以将本地仓库安装到Maven仓库中。如对前面我们讲过的hello-world项目执行mvn clean install(Eclipse中命令为clean install),结果如下:

    [INFO] Scanning for projects...
    [INFO]                                                                         
    [INFO] ------------------------------------------------------------------------
    [INFO] Building hello-world 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello-world ---
    [INFO] Deleting D:\code\maven\hello-world\target
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\main\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ hello-world ---
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:\code\maven\hello-world\target\classes
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\test\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ hello-world ---
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:\code\maven\hello-world\target\test-classes
    [INFO] 
    [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-world ---
    [INFO] Surefire report directory: D:\code\maven\hello-world\target\surefire-reports
    
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running com.alvinliang.maven.HelloWorldTest
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.661 sec
    
    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] 
    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ hello-world ---
    [INFO] Building jar: D:\code\maven\hello-world\target\hello-world-0.0.1-SNAPSHOT.jar
    [INFO] 
    [INFO] --- maven-install-plugin:2.4:install (default-install) @ hello-world ---
    [INFO] Installing D:\code\maven\hello-world\target\hello-world-0.0.1-SNAPSHOT.jar to D:\library\maven\repository\com\alvinliang\maven\hello-world\0.0.1-SNAPSHOT\hello-world-0.0.1-SNAPSHOT.jar
    [INFO] Installing D:\code\maven\hello-world\pom.xml to D:\library\maven\repository\com\alvinliang\maven\hello-world\0.0.1-SNAPSHOT\hello-world-0.0.1-SNAPSHOT.pom
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 13.245s
    [INFO] Finished at: Thu Nov 28 22:22:25 CST 2013
    [INFO] Final Memory: 10M/55M
    [INFO] ------------------------------------------------------------------------
    从上述输出,我们可以看到构件的hello-world-0.0.1-SNAPSHOT.jar,安装到了本地仓库D:\library\maven\repository下。


    2)远程仓库
    本地仓库好比书房,而远程仓库就像是书店。对于Maven来说,每个用户只有一个本地仓库,但是可以配置多个远程仓库。

    a.中央仓库
    Maven必须要知道至少一个可用的远程仓库,中央仓库就是这样一个默认的远程仓库,Maven的安装文件自带了中央仓库的配置。在settings文件有如下配置:

    中央仓库包含了这个世界的绝大多数流行的开源Java构件,源码等。

    b)私服
    私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件的时候,它先从私服请求,如果私服上没有构件,测从外部的远程仓库下载,存在私服上,再为Maven用户下载。现在可以使用最流行的Maven私服软件--Nexus。后面专门介绍如何搭建私服。

    3. 远程仓库的配置

    见如下代码清单:

    <repositories>
      	<repository>
      		<id>central</id>
      		<name>Central Repository</name>
      		<url>https://nexus/sourcesense.com/nexus/content/repositories/public/</url>
      		<layout>default</layout>
      		<snapshots>
      			<enabled>false</enabled>
      		</snapshots>
      	</repository>
    <repositories>

    注意上面的id设置为central,使用nexus官方的仓库地址来代替中央仓库,因为有时候中央仓库很慢。上述配置中设置snapshots为false表示关闭central仓库对快照版本的下载支持。

    4. 远程仓库的认证

    在局部文件settings.xml中,在servers元素下配置,如下:

     <servers>
        <server>
          <id>central</id>
          <username>lb</username>
          <password>123456</password>
        </server>
    <servers>

    上述配置中id为关键元素,表示对那个远程仓库进行认证,这里配置的是中央仓库central。其中认证的用户名为lb,密码为123456。

    5. 镜像

    如果仓库X可以提供仓库Y存储的所有内容,那么就可以认为X是Y的一个镜像。也就是说,任何一个可以从仓库Y获得的构件,都可以从它的镜像中获取。例如:http://maven.net.cn/content/groups/public/是重要仓库http://repo1.maven.org/maven2/在中国的镜像。由于地理位置的原因,镜像玩玩能够提供比中央仓库更快的服务。下面就是本人使用Nexus镜像来代替中央仓库的配置,编辑settings.xml,如下:

      <mirrors>
      
        <mirror>
          <id>central</id>
          <mirrorOf>*</mirrorOf>
          <name>Human Readable Name for this Mirror.</name>
          <url>http://localhost:8081/nexus/content/groups/public/</url>
        </mirror>
    	
        <!-- mirror
         | Specifies a repository mirror site to use instead of a given repository. The repository that
         | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used
         | for inheritance and direct lookup purposes, and must be unique across the set of mirrors.
         |
        <mirror>
          <id>mirrorId</id>
          <mirrorOf>repositoryId</mirrorOf>
          <name>Human Readable Name for this Mirror.</name>
          <url>http://my.repository.com/repo/path</url>
        </mirror>
         -->
      </mirrors>

    上述配置中,mirrorOf指的是为那个仓库提供镜像,如果设置为central,表示为中央仓库的镜像,设置为*表示为任意仓库设置的镜像配置。

    6. 仓库搜索服务

    最后我们在为Maven编写依赖的时候,是不是不知道从何处开始,如何寻找到需要的依赖呢?下面我提供几个非常不错的网址:
    http://mvnrepository.com/ 

    https://repository.sonatype.org/

    打开其中一个页面,直接搜索关键字,可以得到依赖配置,如下图:

    发布于 3年前, 阅读(846) | 评论(0) | 投票(0) | 收藏(14) 阅读全文...
  • 252013-11

    接下来介绍一下Maven的坐标和依赖。

    1. Maven坐标

      依赖的底层基础就是坐标。在实际生活中我们可以将地址看成一种坐标。而Maven为构件引入坐标的概念。以前当我们需要Spring Framework依赖的时候,就回去Spring官网查找,当需要log4j的依赖时,我们又回去Apache网站查找,这样就花费大量的时间在搜索、浏览网页上。现在Maven定义了一组规则:世界上任何一个构件都可以使用Maven坐标唯一标识。Maven坐标元素包括:groupId, artifactId, version, packaging, classifier。

    2. 坐标详解

    1)groupId: 定义当前Maven项目隶属的实际项目。groupId的表示方式与Java报名的表示方式类似,通常与域名反向一一对应。如:org.springframework.
    2)artifactId: 该元素定义实际项目的一个Maven项目(模块),推荐使用实际项目名称作为artifactId的前缀。如:spring-core. 默认情况下Maven生成的构件会以artifactId作为开头,如spring-core-3.1.0.jar。
    3)version: 该元素定义Maven项目当前所处的项目的版本。
    4)packaging: 该元素定义Maven项目的打包方式。当不定义packaging的时候,Maven会使用默认值jar。
    5)classifier: 该元素用来帮助定义构建输出的一些附属软件。
    以上5个元素中,groupId、artifactId、version是必须定义的,packaging是可选的,而classifier是不能直接定义的。

    3. 依赖配置

    <project>
      <dependencies>
        <dependency>
          <groupId>...</groupId>
          <artifactId>...</artifactId>
          <version>...</version>
          <type>...</type>
          <scope>...</scope>
          <optional>...</optional>
          <exclusions>
            <exclusion>
            ...
            </exclusion>
          </exclusions>
        </dependency>
      </dependencies>
    </project>

    每个依赖都包括的元素有:
    groupId、artifactId和version:依赖的基本坐标。
    type: 依赖的类型,对应于项目坐标定义的packagin。大多情况下不必声明。
    scope: 依赖的范围。
    optional: 标记依赖时候可选。
    exclusions: 用来配出传递性依赖。

    4. 依赖范围

    1)compile:编译依赖范围。该依赖对于编译、测试、运行三种classpath都有效。如spring-core。

    2)test:测试依赖范围。只对测试范围classpath有效。经典的例子是JUnit。

    3)provided:已提供依赖范围,对编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,在编译和测试项目的时候需要该依赖,但是在运行项目时,由于容器已经提供,就不要重复引入。

    4)runtime:运行时依赖。对于测试和运行classpath有效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口。

    5)system:系统依赖范围。与classpath的关系和provided一样。

    6)import:导入依赖范围。该依赖范围不会对三种classpath产生实际的影响。

    5. 依赖的传递性

    顾名思义,很多人都知道A->B, B->C,那么A->C.但是在Maven中传递的范围是会改变的,这个由maven自身处理。如下图:
    第一列为第一依赖,第一行为第二依赖,单元格内为传递范围。

      compile test provided runtime
    compile compile - - runtime
    test test - - test
    provided provided - provided provided
    runtime runtime - - runtime

    6. 依赖调解

    如果有多个相同的依赖,Maven会根据一定的规则来确定:
    传递路径长度取最短原则,传递路径长度相等时,采取最先申明原则。

    7. 排除依赖


    依赖包里有些包不稳定,可以排除该依赖包,如:
    <dependency>
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>1.4.1</version>
      <exclusions>
        <exclusion>
          <groupId>javax.activation</groupId>
          <artifactId>activation</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>javax.activation</groupId>
      <artifactId>activation</artifactId>
      <version>1.1</version>
    </dependency>


    8. 分类依赖

    当同一个模块,所依赖的几个模块版本都相同时,可以使用maven里的属性做分类依赖,依赖版本升级时改一处即可。

    <properties>
      <springframework.version>3.2.5</springframework.version>
    </properties>
    <dependencies>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${springframework.version}</version>
        <type>jar</type>
        <scope>compile</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${springframework.version}</version>
        <type>pom</type>
        <scope>compile</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${springframework.version}</version>
        <type>jar</type>
        <scope>compile</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${springframework.version}</version>
        <type>jar</type>
        <scope>compile</scope>
      </dependency>
    </dependencies>


    9. 优化依赖


    1) mvn dependency:list

    查出依赖列表
    2) mvn dependency:tree
    查出依赖列表,按tree排列
    3) mvn dependency:analyze
    查找出在编译和测试中未使用但显示声明的依赖  

    发布于 3年前, 阅读(346) | 评论(0) | 投票(0) | 收藏(2) 阅读全文...
  • 212013-11

    1. 什么是POM

    Maven项目的核心是pom.xml, POM(Project Object Model)定义了项目的基本信息,用于描述项目如何构建、声明项目依赖等等。

    首先我们使用Eclipse新建一个Maven项目,项目名为hello-world,如下图:

    在pom.xml中最重要几个重要的元素有groupId、artifactId、version、dependencies等。

    groupId:定义了项目属于哪个组,该组一般和项目所在的组织或公司有关。比如你在googlecode上建立一个名为myapp的项目,那么groupId为com.googlecode.myapp。

    artifactId: 定义了当前Maven项目中中唯一的ID,比如前面的groupId为com.googlecode.myapp,我们可以为不同的子项目或者模块分配不同的artifactId,如myapp-util, myapp-dao,myapp-web等。

    version: 指定了项目当前的版本。SNAPSHOT意为快照,表示项目还在开发中,还不稳定。

    dependencies: 该元素下可以包含多个dependency以声明项目的依赖。这里添加了一个依赖--groupId为junit,artifactId为junit,version为4.10.有了这段声明Maven会自动从中央仓库下载junit-4.10.jar。

    2. 编写代码

    1) Maven项目的主代码位于src/main/java目录中,在上图中我们可以看到。代码编写完毕后,右键pom.xml --> Run as -->Maven build,在Goals输入 clean compile,会得到如下结果:

    [INFO] Scanning for projects...
    [INFO]                                                                         
    [INFO] ------------------------------------------------------------------------
    [INFO] Building hello-world 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello-world ---
    [INFO] Deleting D:\code\maven\hello-world\target
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\main\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ hello-world ---
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:\code\maven\hello-world\target\classes
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 2.567s
    [INFO] Finished at: Thu Nov 21 22:13:29 CST 2013
    [INFO] Final Memory: 9M/101M
    [INFO] ------------------------------------------------------------------------

    2) 测试代码位于独立的目录中,默认的测试代码目录是src/test/java,编写测试代码:
    package com.alvinliang.maven;
    
    import static org.junit.Assert.assertEquals;
    import org.junit.Test;
    
    public class HelloWorldTest {
    	
    	@Test
    	public void testSayHello() {
    		HelloWorld helloWorld = new HelloWorld();
    		String result = helloWorld.sayHello();
    		assertEquals("Hello World", result);
    	}
    }
    之后调用Maven执行测试,右键pom.xml --> Run as --> Maven build, 在goals中输入clean test:
    [INFO] Scanning for projects...
    [INFO]                                                                         
    [INFO] ------------------------------------------------------------------------
    [INFO] Building hello-world 0.0.1-SNAPSHOT
    [INFO] ------------------------------------------------------------------------
    [INFO] 
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ hello-world ---
    [INFO] Deleting D:\code\maven\hello-world\target
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\main\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ hello-world ---
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:\code\maven\hello-world\target\classes
    [INFO] 
    [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-world ---
    [WARNING] Using platform encoding (GBK actually) to copy filtered resources, i.e. build is platform dependent!
    [INFO] skip non existing resourceDirectory D:\code\maven\hello-world\src\test\resources
    [INFO] 
    [INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ hello-world ---
    [WARNING] File encoding has not been set, using platform encoding GBK, i.e. build is platform dependent!
    [INFO] Compiling 1 source file to D:\code\maven\hello-world\target\test-classes
    [INFO] 
    [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ hello-world ---
    [INFO] Surefire report directory: D:\code\maven\hello-world\target\surefire-reports
    
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running com.alvinliang.maven.HelloWorldTest
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.055 sec
    
    Results :
    
    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 5.214s
    [INFO] Finished at: Thu Nov 21 22:35:11 CST 2013
    [INFO] Final Memory: 11M/101M
    [INFO] ------------------------------------------------------------------------

    这样我们就学会如何简单的使用Maven新建项目了,重点要理解POM的基本概念。 

    ×
    复制
    复制全部
    0
    0

    查看评论
    * 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
      个人资料
      • 访问:228102次
      • 积分:2621
      • 等级:
      • 排名:第13927名
      • 原创:6篇
      • 转载:54篇
      • 译文:55篇
      • 评论:32条
      文章分类
      最新评论