Spring 2.x: Datenbanken und Transaktionen

+ andere TechDocs
+ Java, JEE, EJB
+ Spring 2.x: DI + AOP
+ Spring 2.x: Remote
+ Spring 2.x: MVC
+ Springframework.org
+


Zweiter Teil zu Spring 2.x:
Datenbanken und Transaktionen.

    

Weitere Spring-Themen:



Inhalt

  1. Einfaches Datenbank-Programmierbeispiel mit dem Spring JdbcTemplate
    AdresseTO, MeineAdresseDaoIf, MeineAdresseDaoImpl, MainDb, db.xml, build-db.xml, Projektverzeichnis, Ausführung, Bemerkungen
  2. Einfaches Datenbank-Programmierbeispiel mit deklarativer Transaktionssteuerung
    MeinTxTestIf, MeinTxTestImpl, MainTx, tx.xml, Projektverzeichnis, Ausführung, Bemerkungen


Einfaches Datenbank-Programmierbeispiel mit dem Spring JdbcTemplate

  1. Lesen Sie die Vorbemerkungen zu TO, DAO und JdbcTemplate.
  2. Führen Sie die unter Installation genannten Schritte durch.
  3. Installieren Sie zusätzlich Ant wie zum Beispiel hier beschrieben.
  4. Das folgende Beispiel benötigt eine Datenbank. Installieren Sie zum Beispiel MySQL wie beschrieben unter: mysql.htm#InstallationUnterWindows. Das Beispiel geht davon aus, dass Sie als 'Database-Name' "MeineDb" wählen ("CREATE DATABASE MeineDb;"). Sie können das Beispiel natürlich auch an andere Datenbanken oder Database-Namen anpassen. Downloaden Sie den zu Ihrer Datenbank passenden JDBC-Treiber, für MySQL z.B. 'mysql-connector-java-5.1.16-bin.jar' aus 'mysql-connector-java-5.1.16.zip'.
  5. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Transferobjekt-JavaBean-Datei 'AdresseTO.java':

    package beispieldb;
    
    public class AdresseTO
    {
      private Long    id;
      private String  name;
      private Integer plz;
      private String  ort;
    
      public AdresseTO( long id, String name, int plz, String ort )
      {
        this.id   = new Long( id );
        this.name = name;
        this.plz  = new Integer( plz );
        this.ort  = ort;
      }
    
      public String toString()
      {
        return "id=" + id + ", Name=" + name + ", Plz=" + plz + ", Ort=" + ort + "; ";
      }
    
      public Long    getId()   { return id; }
      public String  getName() { return name; }
      public Integer getPlz()  { return plz; }
      public String  getOrt()  { return ort; }
      public void setId(   Long    id )   { this.id   = id; }
      public void setName( String  name ) { this.name = name; }
      public void setPlz(  Integer plz )  { this.plz  = plz; }
      public void setOrt(  String  ort )  { this.ort  = ort; }
    }
    
  6. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Data-Access-Object-Interface-Datei 'MeineAdresseDaoIf.java':

    package beispieldb;
    
    public interface MeineAdresseDaoIf
    {
      public void deleteDbTable();
      public void createDbTable();
      public void insertAdresse( AdresseTO adresseTO );
      public AdresseTO findAdresseById( long id );
      public AdresseTO[] findAdressenByName( String name );
      public int countAdressenAusOrt( String ort );
    }
    
  7. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Data-Access-Object-Implementierungsdatei 'MeineAdresseDaoImpl.java':

    package beispieldb;
    
    import java.sql.*;
    import java.util.List;
    import org.springframework.jdbc.core.*;
    import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
    
    public class MeineAdresseDaoImpl implements MeineAdresseDaoIf
    {
      private DataFieldMaxValueIncrementer incrementer;
      private JdbcTemplate jdbcTemplate;
    
      public void initMethod()
      {
      }
    
      public void createDbTable()
      {
        jdbcTemplate.execute( "Create Table if not exists MeineAdressen ( " +
            "id Integer primary Key, Name Varchar(80), Plz Integer, Ort Varchar(80) ) ENGINE=InnoDB" );
        jdbcTemplate.execute( "Create Table if not exists MeineAdressen_Sequence ( id Integer ) ENGINE=InnoDB" );
        jdbcTemplate.update( "Insert into MeineAdressen_Sequence values( 0 )" );
      }
    
      public void deleteDbTable()
      {
        jdbcTemplate.execute( "Drop Table if exists MeineAdressen" );
        jdbcTemplate.execute( "Drop Table if exists MeineAdressen_Sequence" );
      }
    
      public void insertAdresse( AdresseTO adresseTO )
      {
        Long id = new Long( incrementer.nextLongValue() );
        jdbcTemplate.update( "Insert into MeineAdressen ( id, Name, Plz, Ort ) values (?, ?, ?, ?)",
            new Object[] { id, adresseTO.getName(), adresseTO.getPlz(), adresseTO.getOrt() } );
        adresseTO.setId( id );
      }
    
      public AdresseTO findAdresseById( long id )
      {
        return (AdresseTO) jdbcTemplate.query( "Select * from MeineAdressen where id = ?",
            new Object[] { new Long( id ) },
            new ResultSetExtractor() {
              public Object extractData( ResultSet rs ) throws SQLException {
                if( !rs.next() ) return null;
                return new AdresseTO( rs.getLong( "id" ), rs.getString( "Name" ),
                                      rs.getInt( "Plz" ), rs.getString( "Ort" ) );
              }
            } );
      }
    
      public AdresseTO[] findAdressenByName( String name )
      {
        List lst = jdbcTemplate.query( "Select * from MeineAdressen where Name like ?",
            new Object[] { name },
            new RowMapper() {
              public Object mapRow( ResultSet rs, int rowNum ) throws SQLException {
                return new AdresseTO( rs.getLong( "id" ), rs.getString( "Name" ),
                                      rs.getInt( "Plz" ), rs.getString( "Ort" ) );
              }
            } );
        return (AdresseTO[]) lst.toArray( new AdresseTO[lst.size()] );
      }
    
      public int countAdressenAusOrt( String ort )
      {
        return jdbcTemplate.queryForInt( "Select count(*) from MeineAdressen where Ort = ?",
                                         new Object[] { ort } );
      }
    
      public void setJdbcTemplate( JdbcTemplate jdbcTemplate )
      {
        this.jdbcTemplate = jdbcTemplate;
      }
    
      public void setIncrementer( DataFieldMaxValueIncrementer incrementer )
      {
        this.incrementer = incrementer;
      }
    }
    
  8. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Haupt-Java-Datei 'MainDb.java':

    package beispieldb;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainDb
    {
      private static final AdresseTO[] adrUrladung = {
        new AdresseTO( 0, "Achim",     52078, "Aachen" ),
        new AdresseTO( 0, "Alexander", 52134, "Herzogenrath" ),
        new AdresseTO( 0, "Helmut",    52066, "Aachen" ),
        new AdresseTO( 0, "Josef",     52070, "Aachen" ),
        new AdresseTO( 0, "Manfred",   52146, "Wuerselen" ),
        new AdresseTO( 0, "Patrick",   52074, "Aachen" ),
        new AdresseTO( 0, "Roland",    52134, "Herzogenrath" ),
        new AdresseTO( 0, "Torsten",   52072, "Aachen" ),
        new AdresseTO( 0, "Werner",    52066, "Aachen" )
      };
    
      public static void main( String[] args )
      {
        ApplicationContext appContext =
          new ClassPathXmlApplicationContext( "beispieldb/db.xml" );
        System.out.println( "\n-------- MainDb --------" );
        MeineAdresseDaoIf dao = (MeineAdresseDaoIf) appContext.getBean( "idMeineAdresseDao" );
        dao.deleteDbTable();
        dao.createDbTable();
        for( int i=0; i<adrUrladung.length; i++ ) {
          dao.insertAdresse( adrUrladung[i] );
        }
        System.out.println( "AdresseById(8):    " + dao.findAdresseById( 8 ) );
        AdresseTO[] adrArr = dao.findAdressenByName( "%a%" );
        for( int i=0; i<adrArr.length; i++ ) {
          System.out.println( "AdressenByName["+i+"]: " + adrArr[i] );
        }
        System.out.println( "countAdressenAusOrt(Aachen): "
                            + dao.countAdressenAusOrt( "Aachen" ) );
      }
    }
    
  9. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Spring-XML-Konfigurationsdatei 'db.xml':

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
      "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
      <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="beispieldb/db.properties" />
      </bean>
      <bean id="idMeineAdresseDao" class="beispieldb.MeineAdresseDaoImpl"
            init-method="initMethod"  singleton="true">
        <property name="incrementer"  ref="idMeineAdresseIncr" />
        <property name="jdbcTemplate" ref="idJdbcTemplate" />
      </bean>
      <bean id="idMeineAdresseIncr"
            class="org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer">
        <property name="columnName"      value="id" />
        <property name="incrementerName" value="MeineAdressen_Sequence" />
        <property name="dataSource"      ref="idDataSource" />
      </bean>
      <bean id="idJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="idDataSource" />
      </bean>
      <bean id="idDataSource"
            class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close">
        <property name="driverClassName" value="${db.driverClassName}" />
        <property name="url"             value="${db.url}" />
        <property name="username"        value="${db.username}" />
        <property name="password"        value="${db.password}" />
      </bean>
      <!-- Falls DataSource ueber JNDI-Lookup ueber Application Server:
      <bean id="idDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/myDataSource" />
      </bean>
      -->
    </beans>
    
  10. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Property-Datei 'db.properties':

    db.driverClassName=com.mysql.jdbc.Driver
    db.url=jdbc:mysql://localhost:3306/MeineDb
    db.username=root
    db.password=mysqlpwd
    
  11. Erzeugen Sie im Projektverzeichnis '<MeinSpringProjekt>' folgende Ant-XML-Datei 'build-db.xml':

    <project name="MeinSpringProjekt - JdbcTemplate" default="run">
      <property name="myAppClass" value="beispieldb.${Main}" />
      <property name="mySrcDir"   value="${basedir}/src" />
      <property name="myDestDir"  value="${basedir}/bin" />
      <property name="myLibDir"   value="${basedir}/lib" />
      <target name="compile">
        <javac srcdir="${mySrcDir}" destdir="${myDestDir}" debug="on">
          <classpath>
            <fileset dir="${myLibDir}">
              <include name="*.jar" />
            </fileset>
          </classpath>
        </javac>
      </target>
      <target name="copy-resources">
        <copy todir="${myDestDir}">
          <fileset dir="${mySrcDir}">
            <exclude name="**/*.java" />
          </fileset>
        </copy>
      </target>
      <target name="run" depends="compile,copy-resources">
        <java fork="true" classname="${myAppClass}">
          <classpath>
            <fileset dir="${myLibDir}">
              <include name="*.jar" />
            </fileset>
            <pathelement path="${myDestDir}" />
          </classpath>
          <arg line="${args}" />
        </java>
      </target>
    </project>
    
  12. Ihr Projektverzeichnis sollte jetzt in etwa folgendermaßen aussehen (ergänzen Sie fehlende .jar-Libraries aus 'spring-framework...\lib\jakarta-commons' aus dem Spring-Archiv):

    [\MeinWorkspace]
      '- [MeinSpringProjekt]
           |- [bin]
           |- [lib]
           |    |- commons-collections.jar
           |    |- commons-dbcp.jar
           |    |- commons-logging.jar
           |    |- commons-pool.jar
           |    |- mysql-connector-java-5.1.16-bin.jar
           |    '- spring.jar
           |- [src]
           |    '- [beispieldb]
           |         |- AdresseTO.java
           |         |- db.properties
           |         |- db.xml
           |         |- MainDb.java
           |         |- MeineAdresseDaoIf.java
           |         '- MeineAdresseDaoImpl.java
           '- build-db.xml
    
  13. Passen Sie in der 'db.properties' (und eventuell in der 'db.xml') die Properties an Ihre Gegebenheiten an.

    Bevor Sie dieses Beispiel starten, müssen Sie überprüfen, ob es in Ihrer Datenbank eventuell bereits gleichnamige Tabellen gibt. Diese werden ohne Rückfrage gelöscht!

    Kompilation und Ausführung können folgendermaßen im Kommandozeilenfenster aus dem Projektverzeichnis '<MeinSpringProjekt>' heraus erfolgen:

    cd \MeinWorkspace\MeinSpringProjekt

    ant -f build-db.xml -DMain=MainDb

  14. Natürlich können Sie dieses Projekt auch in Eclipse laden und bearbeiten. Verfahren Sie wie hier beschrieben. Achten Sie darauf, dass alle benötigten .jar-Libs im 'Java Build Path' eingetragen sind.
  15. Sie erhalten folgendes Ergebnis:

    -------- MainDb --------
    AdresseById(8):    id=8, Name=Torsten, Plz=52072, Ort=Aachen;
    AdressenByName[0]: id=1, Name=Achim, Plz=52078, Ort=Aachen;
    AdressenByName[1]: id=2, Name=Alexander, Plz=52134, Ort=Herzogenrath;
    AdressenByName[2]: id=5, Name=Manfred, Plz=52146, Ort=Wuerselen;
    AdressenByName[3]: id=6, Name=Patrick, Plz=52074, Ort=Aachen;
    AdressenByName[4]: id=7, Name=Roland, Plz=52134, Ort=Herzogenrath;
    countAdressenAusOrt(Aachen): 6
    
  16. Ändern Sie den Suchausdruck in 'dao.findAdressenByName("%a%")' in 'MainDb.main()' um andere Ergebnisse zu finden.
  17. Bemerkungen:



Einfaches Datenbank-Programmierbeispiel mit deklarativer Transaktionssteuerung

  1. Allgemeine Informationen zu Transaktionen finden Sie in jee-transaktionen.htm.
  2. Dieses Beispiel basiert auf dem vorherigen Datenbankbeispiel. Führen Sie die oben unter Einfaches Datenbank-Programmierbeispiel mit dem Spring JdbcTemplate genannten Schritte durch.
  3. MySQL verwendet defaultmäßig die 'MyISAM'-Engine, die aber keine Transaktionen unterstützt und deshalb für dieses Beispiel ungeeignet ist. Wir wollen die 'InnoDB'-Engine verwenden: Öffnen Sie die zu MySQL gehörende 'my.ini'- oder 'my.cnf'-Datei, zum Beispiel in den Verzeichnissen '/etc/mysql', 'C:\', 'C:\Windows' oder 'C:\Programme\MySQL\MySQL Server 4.1'. Stellen Sie sicher dass nicht 'skip-innodb' gesetzt ist und kontrollieren Sie die anderen 'InnoDB Specific options' (z.B. 'innodb_data_file_path=ibdata:30M').
  4. Achten Sie darauf, dass beim Generieren der Datenbanktabellen die transaktionsfähige Datenbank-Engine gewählt wird. Im Beispiel erfolgt dies durch die Angabe 'ENGINE=InnoDB' in 'MeineAdresseDaoImpl.createDbTable()'.
  5. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Interface-Datei 'MeinTxTestIf.java':

    package beispieldb;
    
    public interface MeinTxTestIf
    {
      public void insertTestMitRequiredTx( AdresseTO adresseTO );
      public void rollbackTestMitRequiredTx( AdresseTO adresseTO );
      public void exceptionTestMitRequiredTx( AdresseTO adresseTO );
      public MeineAdresseDaoIf getMeineAdresseDao();
      public void setMeineAdresseDao( MeineAdresseDaoIf meineAdresseDao );
    }
    
  6. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Implementierungsdatei 'MeinTxTestImpl.java':

    package beispieldb;
    
    import org.springframework.transaction.interceptor.TransactionAspectSupport;
    
    public class MeinTxTestImpl implements MeinTxTestIf
    {
      private MeineAdresseDaoIf meineAdresseDao;
    
      public void insertTestMitRequiredTx( AdresseTO adresseTO )
      {
        meineAdresseDao.insertAdresse( adresseTO );
      }
    
      public void rollbackTestMitRequiredTx( AdresseTO adresseTO )
      {
        meineAdresseDao.insertAdresse( adresseTO );
        if( null != TransactionAspectSupport.currentTransactionStatus() )
          TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }
    
      public void exceptionTestMitRequiredTx( AdresseTO adresseTO )
      {
        meineAdresseDao.insertAdresse( adresseTO );
        throw new RuntimeException( "Erwartete Test-Exception" );
      }
    
      public MeineAdresseDaoIf getMeineAdresseDao()
      {
        return meineAdresseDao;
      }
    
      public void setMeineAdresseDao( MeineAdresseDaoIf meineAdresseDao )
      {
        this.meineAdresseDao = meineAdresseDao;
      }
    }
    
  7. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Haupt-Java-Datei 'MainTx.java':

    package beispieldb;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MainTx
    {
      public static void main( String[] args )
      {
        ApplicationContext appContext =
          new ClassPathXmlApplicationContext( "beispieldb/tx.xml" );
        System.out.println( "\n-------- MainTx --------" );
        MeinTxTestIf meinTxTest = (MeinTxTestIf) appContext.getBean( "idMeinTxTest" );
        MeineAdresseDaoIf dao = meinTxTest.getMeineAdresseDao();
        dao.deleteDbTable();
        dao.createDbTable();
    
        meinTxTest.insertTestMitRequiredTx( new AdresseTO( 0, "InsertTest1", 0, "" ) );
    
        meinTxTest.rollbackTestMitRequiredTx( new AdresseTO( 0, "RollbackTest", 0, "" ) );
    
        try {
          meinTxTest.exceptionTestMitRequiredTx( new AdresseTO( 0, "ExceptionTest", 0, "" ) );
        } catch( RuntimeException ex) {
          // Diese Exception ist geplant:
          System.out.println( ex );
        }
    
        meinTxTest.insertTestMitRequiredTx( new AdresseTO( 0, "InsertTest2", 0, "" ) );
    
        AdresseTO[] adrArr = dao.findAdressenByName( "%" );
        for( int i=0; i<adrArr.length; i++ ) {
          System.out.println( "AdressenByName["+i+"]: " + adrArr[i] );
        }
      }
    }
    
  8. Erzeugen Sie im Package-Verzeichnis 'beispieldb' folgende Spring-XML-Konfigurationsdatei 'tx.xml':

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
      "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
      <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="beispieldb/db.properties" />
      </bean>
      <bean id="idMeinTxTest" class="beispieldb.MeinTxTestImpl">
        <property name="meineAdresseDao" ref="idMeineAdresseDao" />
      </bean>
      <bean id="idMeineAdresseDao" class="beispieldb.MeineAdresseDaoImpl"
            init-method="initMethod"  singleton="true">
        <property name="incrementer"  ref="idMeineAdresseIncr" />
        <property name="jdbcTemplate" ref="idJdbcTemplate" />
      </bean>
      <bean id="idMeineAdresseIncr"
            class="org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer">
        <property name="columnName"      value="id" />
        <property name="incrementerName" value="MeineAdressen_Sequence" />
        <property name="dataSource"      ref="idDataSource" />
      </bean>
      <bean id="idJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="idDataSource" />
      </bean>
      <bean id="idDataSource"
            class="org.apache.commons.dbcp.BasicDataSource"
            destroy-method="close">
        <property name="driverClassName" value="${db.driverClassName}" />
        <property name="url"             value="${db.url}" />
        <property name="username"        value="${db.username}" />
        <property name="password"        value="${db.password}" />
      </bean>
      <!-- Falls DataSource ueber JNDI-Lookup ueber Application Server:
      <bean id="idDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="java:comp/env/jdbc/myDataSource" />
      </bean>
      -->
    
      <bean id="idAutoProxyCreator"
            class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="interceptorNames"><list>
          <idref local="idTransactionInterceptor"></idref>
        </list></property>
        <property name="beanNames"><list>
          <idref local="idMeinTxTest" />
          <idref local="idMeineAdresseDao" />
        </list></property>
      </bean>
      <bean id="idTransactionInterceptor"
            class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="idTransactionManager" />
        <property name="transactionAttributeSource" ref="idTransactionAttributeSource" />
      </bean>
      <bean id="idTransactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="idDataSource" />
      </bean>
      <bean id="idTransactionAttributeSource"
        class="org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource">
        <property name="nameMap">
          <map>
            <entry key="*DbTable"       value="PROPAGATION_REQUIRED" />
            <entry key="insertAdresse*" value="PROPAGATION_REQUIRED" />
            <entry key="findAdresse*"   value="PROPAGATION_REQUIRED" />
            <entry key="countAdressen*" value="PROPAGATION_REQUIRED" />
            <entry key="*RequiredTx"    value="PROPAGATION_REQUIRED" />
            <entry key="*RequiresNewTx" value="PROPAGATION_REQUIRES_NEW" />
          </map>
        </property>
      </bean>
    </beans>
    
  9. Ihr Projektverzeichnis sollte jetzt in etwa folgendermaßen aussehen:

    [\MeinWorkspace]
      '- [MeinSpringProjekt]
           |- [bin]
           |- [lib]
           |    |- commons-collections.jar
           |    |- commons-dbcp.jar
           |    |- commons-logging.jar
           |    |- commons-pool.jar
           |    |- mysql-connector-java-5.1.16-bin.jar
           |    '- spring.jar
           |- [src]
           |    '- [beispieldb]
           |         |- AdresseTO.java
           |         |- db.properties
           |         |- db.xml
           |         |- MainDb.java
           |         |- MainTx.java
           |         |- MeineAdresseDaoIf.java
           |         |- MeineAdresseDaoImpl.java
           |         |- MeinTxTestIf.java
           |         |- MeinTxTestImpl.java
           |         '- tx.xml
           '- build-db.xml
    
  10. Kompilation und Ausführung können folgendermaßen im Kommandozeilenfenster aus dem Projektverzeichnis '<MeinSpringProjekt>' heraus erfolgen:

    cd \MeinWorkspace\MeinSpringProjekt

    ant -f build-db.xml -DMain=MainTx

  11. Natürlich können Sie auch dieses Projekt auch in Eclipse laden und bearbeiten. Verfahren Sie wie hier beschrieben. Achten Sie darauf, dass alle benötigten .jar-Libs im 'Java Build Path' eingetragen sind.
  12. Bemerkungen:





Weitere Themen: andere TechDocs | EJB | SQL | Hibernate
© 1998-2007 Torsten Horn, Aachen